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
213
214
215QXmlStreamEntityResolver::~QXmlStreamEntityResolver()
220
221
222
223
224QString QXmlStreamEntityResolver::resolveEntity(
const QString& ,
const QString& )
231
232
233
234
235
236
237
238
240QString QXmlStreamEntityResolver::resolveUndeclaredEntity(
const QString &)
245#if QT_CONFIG(xmlstreamreader)
247QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(
const QString &name)
250 return entityResolver->resolveUndeclaredEntity(name);
257
258
259
260
261
262
263
264
265
266
267
268void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
270 Q_D(QXmlStreamReader);
271 d->entityResolver = resolver;
275
276
277
278
279
280
281QXmlStreamEntityResolver *QXmlStreamReader::entityResolver()
const
283 Q_D(
const QXmlStreamReader);
284 return d->entityResolver;
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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
437
438
439
440
441QXmlStreamReader::QXmlStreamReader()
442 : d_ptr(
new QXmlStreamReaderPrivate(
this))
447
448
449
450QXmlStreamReader::QXmlStreamReader(QIODevice *device)
451 : d_ptr(
new QXmlStreamReaderPrivate(
this))
457
458
459
460
461
462
463
464
467
468
469
470
471
472
473
474
475
476void QXmlStreamReaderPrivate::appendDataWithEncoding(
const QByteArray &data,
477 QStringDecoder::Encoding enc)
483 if (!dataInfo.empty()) {
484 auto &last = dataInfo.last();
485 if (last.encoding == enc) {
486 last.buffer.append(data);
490 dataInfo.emplace_back(data, enc);
493void QXmlStreamReaderPrivate::addData(
const QByteArray &data, QStringDecoder::Encoding enc)
496 qWarning(
"QXmlStreamReader: addData() with device()");
499 appendDataWithEncoding(data, enc);
503
504
505
506
507
508
509
510QXmlStreamReader::QXmlStreamReader(QAnyStringView data)
511 : d_ptr(
new QXmlStreamReaderPrivate(
this))
513 Q_D(QXmlStreamReader);
514 data.visit([d](
auto data) {
515 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
516 d->appendDataWithEncoding(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
518 QStringDecoder::Utf16);
519 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
520 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
521 QStringDecoder::Latin1);
523 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
524 QStringDecoder::Utf8);
530
531
532
533
534
535QXmlStreamReader::QXmlStreamReader(
const QByteArray &data, PrivateConstructorTag)
536 : d_ptr(
new QXmlStreamReaderPrivate(
this))
538 Q_D(QXmlStreamReader);
539 d->appendDataWithEncoding(data, QStringDecoder::System);
543
544
545QXmlStreamReader::~QXmlStreamReader()
547 Q_D(QXmlStreamReader);
553
554
555
556
559
560
561
562
563
564void QXmlStreamReader::setDevice(QIODevice *device)
566 Q_D(QXmlStreamReader);
567 if (d->deleteDevice) {
569 d->deleteDevice =
false;
577
578
579
580
581
582QIODevice *QXmlStreamReader::device()
const
584 Q_D(
const QXmlStreamReader);
589
590
591
592
593
594
595
596
597
599static bool isDecoderForEncoding(
const QStringDecoder &dec, QStringDecoder::Encoding enc)
604 const QAnyStringView nameView{dec.name()};
605 return !nameView.empty() && nameView == QStringDecoder::nameForEncoding(enc);
609
610
611
612
613
614
615
616
617void QXmlStreamReader::addData(QAnyStringView data)
619 Q_D(QXmlStreamReader);
620 data.visit([d](
auto data) {
621 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
622 d->addData(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
624 QStringDecoder::Utf16);
625 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
626 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Latin1);
628 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Utf8);
634
635
636
637
638
639void QXmlStreamReader::addDataImpl(
const QByteArray &data)
641 Q_D(QXmlStreamReader);
642 d->addData(data, QStringDecoder::System);
646
647
648
649
650
651void QXmlStreamReader::clear()
653 Q_D(QXmlStreamReader);
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677bool QXmlStreamReader::atEnd()
const
679 Q_D(
const QXmlStreamReader);
681 && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError)
682 || (d->type == QXmlStreamReader::EndDocument))) {
684 return d->device->atEnd();
686 return d->dataInfo.empty();
688 return (d->atEnd || d->type == QXmlStreamReader::Invalid);
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710QXmlStreamReader::TokenType QXmlStreamReader::readNext()
712 Q_D(QXmlStreamReader);
713 if (d->type != Invalid) {
714 if (!d->hasCheckedStartDocument)
715 if (!d->checkStartDocument())
718 if (d->atEnd && d->type != EndDocument && d->type != Invalid)
719 d->raiseError(PrematureEndOfDocumentError);
720 else if (!d->atEnd && d->type == EndDocument)
721 d->raiseWellFormedError(QXmlStream::tr(
"Extra content at end of document."));
722 }
else if (d->error == PrematureEndOfDocumentError) {
735
736
737
738
739
740
741
742
743
744QXmlStreamReader::TokenType QXmlStreamReader::tokenType()
const
746 Q_D(
const QXmlStreamReader);
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767bool QXmlStreamReader::readNextStartElement()
769 while (readNext() != Invalid) {
770 if (isEndElement() || isEndDocument())
772 else if (isStartElement())
779
780
781
782
783
784
785
786
787
788
789void QXmlStreamReader::skipCurrentElement()
792 while (depth && readNext() != Invalid) {
795 else if (isStartElement())
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819QString QXmlStreamReader::readRawInnerData()
821 Q_D(QXmlStreamReader);
824 auto specialToEntities = [](QStringView text, QString &output) {
826 QLatin1StringView replacement;
827 const qsizetype sz = text.size();
828 for (qsizetype i = 0; i < sz; ++i) {
829 switch (text[i].unicode()) {
831 replacement =
"<"_L1;
834 replacement =
">"_L1;
837 replacement =
"&"_L1;
840 replacement =
"""_L1;
843 replacement =
"'"_L1;
849 output += text.mid(chunk, i - chunk);
850 output += replacement;
853 if (chunk < text.size())
854 output += text.mid(chunk);
857 if (isStartElement()) {
859 while (!atEnd() && depth) {
860 switch (readNext()) {
862 raw +=
'<'_L1 + name();
863 const QXmlStreamAttributes attrs = attributes();
864 for (
auto it = attrs.begin(); it != attrs.end(); ++it) {
865 raw +=
' '_L1 + it->name() +
"=\""_L1;
866 specialToEntities(it->value(), raw);
876 raw +=
"</"_L1 + name() +
'>'_L1;
880 raw +=
"<![CDATA["_L1 + text() +
"]]>"_L1;
882 specialToEntities(text(), raw);
885 raw +=
"<!--"_L1 + text() +
"-->"_L1;
887 case EntityReference:
888 raw +=
'&'_L1 + name() +
';'_L1;
890 case ProcessingInstruction:
891 raw +=
"<?"_L1 + processingInstructionTarget()
892 +
' '_L1 + processingInstructionData()
898 d->raiseError(NotWellFormedError,
899 QXmlStream::tr(
"Unexpected token while "
900 "reading raw inner data."));
909static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
920 "ProcessingInstruction"
923static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
929
930
931
932
933
934
935
936
937
940void QXmlStreamReader::setNamespaceProcessing(
bool enable)
942 Q_D(QXmlStreamReader);
943 d->namespaceProcessing = enable;
946bool QXmlStreamReader::namespaceProcessing()
const
948 Q_D(
const QXmlStreamReader);
949 return d->namespaceProcessing;
953
954
955
956QString QXmlStreamReader::tokenString()
const
958 Q_D(
const QXmlStreamReader);
959 return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
963
964
965
966static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
968 return QLatin1StringView(QXmlStreamReader_XmlContextString.viewAt(
static_cast<
int>(ctxt)));
973QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
975 tagStack.reserve(16);
976 tagStackStringStorageSize = 0;
977 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
978 namespaceDeclaration.namespaceUri = addToStringStorage(u"http://www.w3.org/XML/1998/namespace");
979 namespaceDeclaration.prefix = addToStringStorage(u"xml");
980 initialTagStackStringStorageSize = tagStackStringStorageSize;
984#if QT_CONFIG(xmlstreamreader)
986QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
990 deleteDevice =
false;
993 state_stack =
nullptr;
995 entityResolver =
nullptr;
997#define ADD_PREDEFINED(n, v)
999 Entity e = Entity::createLiteral(n##_L1, v##_L1);
1000 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e));
1002 ADD_PREDEFINED(
"lt",
"<");
1003 ADD_PREDEFINED(
"gt",
">");
1004 ADD_PREDEFINED(
"amp",
"&");
1005 ADD_PREDEFINED(
"apos",
"'");
1006 ADD_PREDEFINED(
"quot",
"\"");
1007#undef ADD_PREDEFINED
1010void QXmlStreamReaderPrivate::init()
1013 lastAttributeIsCData =
false;
1016 isEmptyElement =
false;
1017 isWhitespace =
true;
1020 hasStandalone =
false;
1022 resumeReduction = 0;
1023 state_stack[tos++] = 0;
1024 state_stack[tos] = 0;
1026 putStack.reserve(32);
1028 textBuffer.reserve(256);
1032 attributes.reserve(16);
1033 lineNumber = lastLineStart = characterOffset = 0;
1036 decoder = QStringDecoder();
1037 attributeStack.clear();
1038 attributeStack.reserve(16);
1039 entityParser.reset();
1040 hasCheckedStartDocument =
false;
1041 normalizeLiterals =
false;
1044 inParseEntity =
false;
1045 referenceToUnparsedEntityDetected =
false;
1046 referenceToParameterEntityDetected =
false;
1047 hasExternalDtdSubset =
false;
1048 lockEncoding =
false;
1049 namespaceProcessing =
true;
1050 rawReadBuffer.clear();
1051 chunkDecoder = QStringDecoder();
1054 tagStackStringStorageSize = initialTagStackStringStorageSize;
1056 type = QXmlStreamReader::NoToken;
1057 error = QXmlStreamReader::NoError;
1058 currentContext = XmlContext::Prolog;
1063
1064
1065
1066void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1068 Q_Q(QXmlStreamReader);
1070 if (value.isEmpty())
1075 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1077 entityParser->init();
1078 entityParser->inParseEntity =
true;
1079 entityParser->readBuffer = value;
1080 entityParser->injectToken(PARSE_ENTITY);
1081 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1082 entityParser->parse();
1083 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1084 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1088inline void QXmlStreamReaderPrivate::reallocateStack()
1091 void *p = realloc(sym_stack, stack_size *
sizeof(Value));
1093 sym_stack =
static_cast<Value*>(p);
1094 p = realloc(state_stack, stack_size *
sizeof(
int));
1096 state_stack =
static_cast<
int*>(p);
1100QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1107inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1109 uint peekc = peekChar();
1110 if (peekc ==
'\n') {
1111 if (putStack.size())
1117 if (peekc == StreamEOF) {
1125
1126
1127
1128inline uint QXmlStreamReaderPrivate::getChar()
1131 if (putStack.size()) {
1132 c = atEnd ? StreamEOF : putStack.pop();
1134 if (readBufferPos < readBuffer.size())
1135 c = readBuffer.at(readBufferPos++).unicode();
1137 c = getChar_helper();
1143inline uint QXmlStreamReaderPrivate::peekChar()
1146 if (putStack.size()) {
1148 }
else if (readBufferPos < readBuffer.size()) {
1149 c = readBuffer.at(readBufferPos).unicode();
1151 if ((c = getChar_helper()) != StreamEOF)
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1172 const qsizetype pos = textBuffer.size();
1173 const auto oldLineNumber = lineNumber;
1176 while ((c = getChar()) != StreamEOF) {
1180 if ((c = filterCarriageReturn()) == 0)
1185 lastLineStart = characterOffset + readBufferPos;
1188 textBuffer += QChar(c);
1191 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1192 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1193 lineNumber = oldLineNumber;
1196 textBuffer += QChar(c);
1201 if (c == uint(*str)) {
1203 if (tokenToInject >= 0)
1204 injectToken(tokenToInject);
1207 if (scanString(str + 1, tokenToInject,
false))
1212 putString(textBuffer, pos);
1213 textBuffer.resize(pos);
1214 lineNumber = oldLineNumber;
1218bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1223 if (c != ushort(str[n])) {
1227 putChar(ushort(str[n]));
1233 textBuffer += QLatin1StringView(str, n);
1235 const qsizetype s = fastScanSpace();
1237 qsizetype pos = textBuffer.size() - n - s;
1238 putString(textBuffer, pos);
1239 textBuffer.resize(pos);
1243 if (tokenToInject >= 0)
1244 injectToken(tokenToInject);
1248bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1250 switch (peekChar()) {
1252 return scanString(spell[CDATA_START], CDATA_START,
false);
1254 return scanString(spell[DOCTYPE], DOCTYPE);
1256 return scanString(spell[ATTLIST], ATTLIST);
1258 return scanString(spell[NOTATION], NOTATION);
1260 if (scanString(spell[ELEMENT], ELEMENT))
1262 return scanString(spell[ENTITY], ENTITY);
1270bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1272 switch (peekChar()) {
1274 return scanString(spell[SYSTEM], SYSTEM);
1276 return scanString(spell[PUBLIC], PUBLIC);
1283bool QXmlStreamReaderPrivate::scanNData()
1285 if (fastScanSpace()) {
1286 if (scanString(spell[NDATA], NDATA))
1293bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1295 switch (peekChar()) {
1297 return scanString(spell[REQUIRED], REQUIRED,
false);
1299 return scanString(spell[IMPLIED], IMPLIED,
false);
1301 return scanString(spell[FIXED], FIXED,
false);
1308bool QXmlStreamReaderPrivate::scanAttType()
1310 switch (peekChar()) {
1312 return scanString(spell[CDATA], CDATA);
1314 if (scanString(spell[ID], ID))
1316 if (scanString(spell[IDREF], IDREF))
1318 return scanString(spell[IDREFS], IDREFS);
1320 if (scanString(spell[ENTITY], ENTITY))
1322 return scanString(spell[ENTITIES], ENTITIES);
1324 if (scanString(spell[NOTATION], NOTATION))
1326 if (scanString(spell[NMTOKEN], NMTOKEN))
1328 return scanString(spell[NMTOKENS], NMTOKENS);
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1351 while ((c = getChar()) != StreamEOF) {
1352 switch (ushort(c)) {
1357
1361 if (filterCarriageReturn() == 0)
1366 lastLineStart = characterOffset + readBufferPos;
1370 if (normalizeLiterals)
1373 textBuffer += QChar(c);
1380 if (!(c & 0xff0000)) {
1390 textBuffer += QChar(ushort(c));
1397inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1401 while ((c = getChar()) != StreamEOF) {
1404 if ((c = filterCarriageReturn()) == 0)
1409 lastLineStart = characterOffset + readBufferPos;
1413 textBuffer += QChar(c);
1425
1426
1427
1428
1429
1430inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1434 while ((c = getChar()) != StreamEOF) {
1435 switch (ushort(c)) {
1442 isWhitespace =
false;
1443 const qsizetype pos = textBuffer.size();
1444 textBuffer += QChar(ushort(c));
1446 while ((c = getChar()) ==
']') {
1447 textBuffer += QChar(ushort(c));
1450 if (c == StreamEOF) {
1451 putString(textBuffer, pos);
1452 textBuffer.resize(pos);
1453 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1454 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1462 if ((c = filterCarriageReturn()) == 0)
1467 lastLineStart = characterOffset + readBufferPos;
1471 textBuffer += QChar(ushort(c));
1476 if (!(c & 0xff0000)) {
1486 isWhitespace =
false;
1487 textBuffer += QChar(ushort(c));
1495inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1499 while ((c = getChar()) != StreamEOF) {
1503 raiseNamePrefixTooLongError();
1504 return std::nullopt;
1533 if (val && val->prefix == n + 1) {
1541 if (val->prefix == 0) {
1542 val->prefix = qint16(n + 2);
1553 textBuffer += QChar(ushort(c));
1560 qsizetype pos = textBuffer.size() - n;
1561 putString(textBuffer, pos);
1562 textBuffer.resize(pos);
1566enum NameChar { NameBeginning, NameNotBeginning, NotName };
1568static const char Begi =
static_cast<
char>(NameBeginning);
1569static const char NtBg =
static_cast<
char>(NameNotBeginning);
1570static const char NotN =
static_cast<
char>(NotName);
1572static const char nameCharTable[128] =
1575 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1576 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1578 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1579 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1581 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1582 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1584 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1585 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1587 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1588 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1590 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1591 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1593 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1594 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1596 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1597 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1600static inline NameChar fastDetermineNameChar(QChar ch)
1602 ushort uc = ch.unicode();
1604 return static_cast<NameChar>(nameCharTable[uc]);
1606 QChar::Category cat = ch.category();
1608 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1609 || cat == QChar::Number_Letter)
1610 return NameBeginning;
1611 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1612 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1613 return NameNotBeginning;
1617inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1621 while ((c = getChar()) != StreamEOF) {
1622 if (fastDetermineNameChar(QChar(c)) == NotName) {
1627 textBuffer += QChar(c);
1631 qsizetype pos = textBuffer.size() - n;
1632 putString(textBuffer, pos);
1633 textBuffer.resize(pos);
1638void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1641 putString(s.mid(from));
1644 putStack.reserve(s.size());
1645 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1646 putStack.rawPush() = it->unicode();
1649void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1651 putStack.reserve(s.size());
1652 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1653 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1656void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1658 putStack.reserve(s.size());
1659 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1660 char16_t c = it->unicode();
1661 if (c ==
'\n' || c ==
'\r')
1662 putStack.rawPush() = ((LETTER << 16) | c);
1664 putStack.rawPush() = c;
1667void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1669 putStack.reserve(s.size());
1670 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1671 char16_t c = it->unicode();
1672 if (c ==
'&' || c ==
';')
1673 putStack.rawPush() = c;
1674 else if (c ==
'\n' || c ==
'\r')
1675 putStack.rawPush() =
' ';
1677 putStack.rawPush() = ((LETTER << 16) | c);
1681uint QXmlStreamReaderPrivate::getChar_helper()
1683 constexpr qsizetype BUFFER_SIZE = 8192;
1684 characterOffset += readBufferPos;
1686 if (readBuffer.size())
1687 readBuffer.resize(0);
1688 if (decoder.isValid())
1691 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1692 if (!decoder.isValid()) {
1694 if (nbytesread < 4) {
1698 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1700 encoding = QStringDecoder::Utf8;
1701 decoder = QStringDecoder(*encoding);
1704 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1706 if (lockEncoding && decoder.hasError()) {
1715 rawReadBuffer.resize(BUFFER_SIZE);
1716 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1717 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1724 if (!tryDecodeWithGlobalDecoder())
1726 }
else if (dataInfo.empty()) {
1730 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1737 if (bufAndEnc.encoding == QStringDecoder::System) {
1739 rawReadBuffer += bufAndEnc.buffer;
1741 rawReadBuffer = bufAndEnc.buffer;
1742 nbytesread = rawReadBuffer.size();
1744 if (!tryDecodeWithGlobalDecoder()) {
1746 bool hasError =
true;
1747 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1748 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1749 hasError = chunkDecoder.hasError();
1752 raiseWellFormedError(
1753 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1758 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1759 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1760 readBuffer = chunkDecoder(bufAndEnc.buffer);
1764 readBuffer.reserve(1);
1766 if (readBufferPos < readBuffer.size()) {
1767 ushort c = readBuffer.at(readBufferPos++).unicode();
1775XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1777 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1778 if (namespaceDeclaration.prefix == prefix) {
1779 return namespaceDeclaration.namespaceUri;
1784 if (namespaceProcessing && !prefix.isEmpty())
1785 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1788 return XmlStringRef();
1794 QStringView namespaceUri;
1796 static AttributeName fromXmlAttribute(
const QXmlStreamAttribute &a,
bool nsProcessing)
1799 return {a.name(), a.namespaceUri()};
1801 return {a.qualifiedName(), a.namespaceUri()};
1804 friend bool operator==(
const AttributeName &lhs,
const AttributeName &rhs)
noexcept
1806 return lhs.name == rhs.name
1807 && lhs.namespaceUri == rhs.namespaceUri;
1809 friend size_t qHash(
const AttributeName &key, size_t seed = 0)
noexcept
1811 return qHashMulti(seed,
1818
1819
1820void QXmlStreamReaderPrivate::resolveTag()
1822 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1823 const qsizetype n = attributeStack.size();
1825 if (namespaceProcessing) {
1826 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1827 if (!dtdAttribute.isNamespaceAttribute
1828 || dtdAttribute.defaultValue.isNull()
1829 || dtdAttribute.tagName != qualifiedName
1830 || dtdAttribute.attributeQualifiedName.isNull())
1833 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1837 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1838 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1839 namespaceDeclaration.prefix.clear();
1841 const XmlStringRef ns(dtdAttribute.defaultValue);
1842 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1843 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1844 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1846 namespaceDeclaration.namespaceUri = ns;
1847 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1848 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1849 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1850 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1851 if (((namespacePrefix ==
"xml"_L1)
1852 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1853 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1854 || namespaceUri.isEmpty()
1855 || namespacePrefix ==
"xmlns"_L1)
1856 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1858 namespaceDeclaration.prefix = namespacePrefix;
1859 namespaceDeclaration.namespaceUri = namespaceUri;
1864 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1866 attributes.resize(n);
1868 Q_DECL_UNINITIALIZED
1869 QDuplicateTracker<AttributeName, 13> names(n);
1871 for (qsizetype i = 0; i < n; ++i) {
1872 QXmlStreamAttribute &attribute = attributes[i];
1873 Attribute &attrib = attributeStack[i];
1874 XmlStringRef prefix(symPrefix(attrib.key));
1875 XmlStringRef name(symString(attrib.key));
1876 XmlStringRef qualifiedName(symName(attrib.key));
1877 XmlStringRef value(symString(attrib.value));
1879 attribute.m_name = name;
1880 attribute.m_qualifiedName = qualifiedName;
1881 attribute.m_value = value;
1883 if (!prefix.isEmpty()) {
1884 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1885 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1888 if (names.hasSeen(AttributeName::fromXmlAttribute(attribute, namespaceProcessing))) {
1889 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1894 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1895 if (dtdAttribute.isNamespaceAttribute
1896 || dtdAttribute.defaultValue.isNull()
1897 || dtdAttribute.tagName != qualifiedName
1898 || dtdAttribute.attributeQualifiedName.isNull())
1901 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1908 QXmlStreamAttribute attribute;
1909 attribute.m_name = dtdAttribute.attributeName;
1910 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1911 attribute.m_value = dtdAttribute.defaultValue;
1913 if (!dtdAttribute.attributePrefix.isEmpty()) {
1914 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1915 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1924 if (namespaceProcessing && names.hasSeen(AttributeName::fromXmlAttribute(attribute,
true))) {
1925 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1929 attribute.m_isDefault =
true;
1930 attributes.append(std::move(attribute));
1934void QXmlStreamReaderPrivate::resolvePublicNamespaces()
1936 const Tag &tag = tagStack.top();
1937 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
1938 publicNamespaceDeclarations.resize(n);
1939 for (qsizetype i = 0; i < n; ++i) {
1940 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
1941 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
1942 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
1943 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
1947void QXmlStreamReaderPrivate::resolveDtd()
1949 publicNotationDeclarations.resize(notationDeclarations.size());
1950 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
1951 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
1952 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
1953 publicNotationDeclaration.m_name = notationDeclaration.name;
1954 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
1955 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
1958 notationDeclarations.clear();
1959 publicEntityDeclarations.resize(entityDeclarations.size());
1960 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
1961 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
1962 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
1963 publicEntityDeclaration.m_name = entityDeclaration.name;
1964 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
1965 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
1966 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
1967 publicEntityDeclaration.m_value = entityDeclaration.value;
1969 entityDeclarations.clear();
1970 parameterEntityHash.clear();
1973uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
1978 if (sym(symbolIndex).c ==
'x')
1979 s = symString(symbolIndex).view().sliced(1).toUInt(&ok, 16);
1981 s = symString(symbolIndex).view().toUInt(&ok, 10);
1983 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
1984 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
1990void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
1994 const char16_t *data = publicId.utf16();
1997 for (i = publicId.size() - 1; i >= 0; --i) {
1999 switch ((c = data[i])) {
2000 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
2001 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
2002 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
2003 case '$':
case '_':
case '%':
case '\'':
case '\"':
2006 if (isAsciiLetterOrNumber(c))
2012 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
2016
2017
2018
2019
2020bool QXmlStreamReaderPrivate::checkStartDocument()
2022 hasCheckedStartDocument =
true;
2024 if (scanString(spell[XML], XML))
2027 type = QXmlStreamReader::StartDocument;
2029 hasCheckedStartDocument =
false;
2030 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2035void QXmlStreamReaderPrivate::startDocument()
2038 if (documentVersion !=
"1.0"_L1) {
2039 if (documentVersion.view().contains(u' '))
2040 err = QXmlStream::tr(
"Invalid XML version string.");
2042 err = QXmlStream::tr(
"Unsupported XML version.");
2044 qsizetype n = attributeStack.size();
2047
2048
2049
2051 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2052 Attribute &attrib = attributeStack[i];
2053 XmlStringRef prefix(symPrefix(attrib.key));
2054 XmlStringRef key(symString(attrib.key));
2055 XmlStringRef value(symString(attrib.value));
2057 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2058 documentEncoding = value;
2061 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2062 if (!QXmlUtils::isEncName(value))
2063 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2065 QByteArray enc = value.toString().toUtf8();
2066 if (!lockEncoding) {
2067 decoder = QStringDecoder(enc.constData());
2068 if (!decoder.isValid()) {
2072 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2073 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2075 decoder = QStringDecoder(QStringDecoder::Utf8);
2076 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2082 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2083 if (!decoder.hasError())
2084 readBuffer = std::move(buf);
2088 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2089 hasStandalone =
true;
2090 if (value ==
"yes"_L1)
2092 else if (value ==
"no"_L1)
2095 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2097 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2102 raiseWellFormedError(err);
2103 attributeStack.clear();
2107void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2109 this->error = error;
2110 errorString = message;
2111 if (errorString.isNull()) {
2112 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2113 errorString = QXmlStream::tr(
"Premature end of document.");
2114 else if (error == QXmlStreamReader::CustomError)
2115 errorString = QXmlStream::tr(
"Invalid document.");
2118 type = QXmlStreamReader::Invalid;
2121void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2123 raiseError(QXmlStreamReader::NotWellFormedError, message);
2126void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2129 raiseError(QXmlStreamReader::NotWellFormedError,
2130 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2134void QXmlStreamReaderPrivate::parseError()
2137 if (token == EOF_SYMBOL) {
2138 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2142 QString error_message;
2143 int ers = state_stack[tos];
2146 if (token != XML_ERROR)
2147 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2148 int k = t_action(ers, tk);
2152 if (nexpected < nmax)
2153 expected[nexpected++] = tk;
2157 if (nexpected && nexpected < nmax) {
2159 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2160 .arg(QLatin1StringView(spell[expected[0]]));
2161 if (nexpected == 2) {
2163 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2164 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2165 }
else if (nexpected > 2) {
2167 for (; s < nexpected - 1; ++s) {
2169 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2170 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2173 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2174 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2176 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2177 .arg(exp_str, QLatin1StringView(spell[token]));
2179 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2182 raiseWellFormedError(error_message);
2185void QXmlStreamReaderPrivate::resume(
int rule) {
2186 resumeReduction = rule;
2187 if (error == QXmlStreamReader::NoError)
2188 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2192
2193
2194
2195qint64 QXmlStreamReader::lineNumber()
const
2197 Q_D(
const QXmlStreamReader);
2198 return d->lineNumber + 1;
2202
2203
2204
2205qint64 QXmlStreamReader::columnNumber()
const
2207 Q_D(
const QXmlStreamReader);
2208 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2212
2213
2214
2215qint64 QXmlStreamReader::characterOffset()
const
2217 Q_D(
const QXmlStreamReader);
2218 return d->characterOffset + d->readBufferPos;
2223
2224
2225QStringView QXmlStreamReader::text()
const
2227 Q_D(
const QXmlStreamReader);
2233
2234
2235
2236
2237
2238QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2240 Q_D(
const QXmlStreamReader);
2241 if (d->notationDeclarations.size())
2242 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2243 return d->publicNotationDeclarations;
2248
2249
2250
2251
2252
2253QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2255 Q_D(
const QXmlStreamReader);
2256 if (d->entityDeclarations.size())
2257 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2258 return d->publicEntityDeclarations;
2262
2263
2264
2265
2266
2267
2268QStringView QXmlStreamReader::dtdName()
const
2270 Q_D(
const QXmlStreamReader);
2271 if (d->type == QXmlStreamReader::DTD)
2273 return QStringView();
2277
2278
2279
2280
2281
2282
2283QStringView QXmlStreamReader::dtdPublicId()
const
2285 Q_D(
const QXmlStreamReader);
2286 if (d->type == QXmlStreamReader::DTD)
2287 return d->dtdPublicId;
2288 return QStringView();
2292
2293
2294
2295
2296
2297
2298QStringView QXmlStreamReader::dtdSystemId()
const
2300 Q_D(
const QXmlStreamReader);
2301 if (d->type == QXmlStreamReader::DTD)
2302 return d->dtdSystemId;
2303 return QStringView();
2307
2308
2309
2310
2311
2312
2313
2314
2315int QXmlStreamReader::entityExpansionLimit()
const
2317 Q_D(
const QXmlStreamReader);
2318 return d->entityExpansionLimit;
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2338 Q_D(QXmlStreamReader);
2339 d->entityExpansionLimit = limit;
2343
2344
2345
2346
2347
2348
2349
2350
2351QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2353 Q_D(
const QXmlStreamReader);
2354 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2355 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2356 return d->publicNamespaceDeclarations;
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2372 Q_D(QXmlStreamReader);
2373 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2374 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2375 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2379
2380
2381
2382
2383
2384
2385void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2387 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2388 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2411 Q_D(QXmlStreamReader);
2412 if (isStartElement()) {
2415 switch (readNext()) {
2417 case EntityReference:
2418 result.insert(result.size(), d->text);
2422 case ProcessingInstruction:
2426 if (behaviour == SkipChildElements) {
2427 skipCurrentElement();
2429 }
else if (behaviour == IncludeChildElements) {
2430 result += readElementText(behaviour);
2435 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2437 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2447
2448
2449
2450void QXmlStreamReader::raiseError(
const QString& message)
2452 Q_D(QXmlStreamReader);
2453 d->raiseError(CustomError, message);
2457
2458
2459
2460
2461QString QXmlStreamReader::errorString()
const
2463 Q_D(
const QXmlStreamReader);
2464 if (d->type == QXmlStreamReader::Invalid)
2465 return d->errorString;
2470
2471
2472
2473QXmlStreamReader::Error QXmlStreamReader::error()
const
2475 Q_D(
const QXmlStreamReader);
2476 if (d->type == QXmlStreamReader::Invalid)
2482
2483
2484QStringView QXmlStreamReader::processingInstructionTarget()
const
2486 Q_D(
const QXmlStreamReader);
2487 return d->processingInstructionTarget;
2491
2492
2493QStringView QXmlStreamReader::processingInstructionData()
const
2495 Q_D(
const QXmlStreamReader);
2496 return d->processingInstructionData;
2502
2503
2504
2505
2506QStringView QXmlStreamReader::name()
const
2508 Q_D(
const QXmlStreamReader);
2513
2514
2515
2516
2517QStringView QXmlStreamReader::namespaceUri()
const
2519 Q_D(
const QXmlStreamReader);
2520 return d->namespaceUri;
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535QStringView QXmlStreamReader::qualifiedName()
const
2537 Q_D(
const QXmlStreamReader);
2538 return d->qualifiedName;
2544
2545
2546
2547
2548
2549
2550QStringView QXmlStreamReader::prefix()
const
2552 Q_D(
const QXmlStreamReader);
2557
2558
2559QXmlStreamAttributes QXmlStreamReader::attributes()
const
2561 Q_D(
const QXmlStreamReader);
2562 return d->attributes;
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2585
2586
2587QXmlStreamAttribute::QXmlStreamAttribute()
2589 m_isDefault =
false;
2593
2594
2595QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2597 m_namespaceUri = namespaceUri;
2598 m_name = m_qualifiedName = name;
2600 m_namespaceUri = namespaceUri;
2604
2605
2606QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2608 qsizetype colon = qualifiedName.indexOf(u':');
2609 m_name = qualifiedName.mid(colon + 1);
2610 m_qualifiedName = qualifiedName;
2615
2616
2617
2618
2620
2621
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2634
2635
2636
2637
2638
2639
2640
2643
2644
2647
2648
2649
2650
2651
2653
2654
2655
2656
2658
2659
2660
2661
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2686
2687
2688
2689
2692
2693
2694
2695
2696
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2714
2715
2716QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2721
2722
2723
2725
2726
2727
2729
2730
2731
2734
2735
2736
2737
2739
2740
2741
2742
2745
2746
2747
2748
2749
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2765
2766
2767
2768
2770
2771
2772
2773
2776
2777
2778QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2783
2784
2785
2786
2787QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2790 m_namespaceUri = namespaceUri;
2794
2795
2796
2798
2799
2800
2806
2807
2808
2809
2810
2813
2814
2815
2816
2817
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2834
2835
2836QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2841
2842
2843
2845
2846
2847
2849
2850
2851
2853
2854
2855
2857
2858
2859
2862
2863
2864
2865
2867
2868
2869
2870
2873
2874
2875
2876
2877
2878
2879QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2881 for (
const QXmlStreamAttribute &attribute : *
this) {
2882 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2883 return attribute.value();
2885 return QStringView();
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2906 for (
const QXmlStreamAttribute &attribute : *
this) {
2907 if (attribute.qualifiedName() == qualifiedName)
2908 return attribute.value();
2910 return QStringView();
2914
2915
2916
2917void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2919 append(QXmlStreamAttribute(namespaceUri, name, value));
2923
2924
2925
2926void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
2928 append(QXmlStreamAttribute(qualifiedName, value));
2931#if QT_CONFIG(xmlstreamreader)
2934
2935
2937
2938
2940
2941
2943
2944
2946
2947
2948
2949
2951
2952
2954
2955
2957
2958
2960
2961
2964
2965
2966
2967
2968bool QXmlStreamReader::isWhitespace()
const
2970 Q_D(
const QXmlStreamReader);
2971 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
2975
2976
2977
2978
2979bool QXmlStreamReader::isCDATA()
const
2981 Q_D(
const QXmlStreamReader);
2982 return d->type == QXmlStreamReader::Characters && d->isCDATA;
2988
2989
2990
2991
2992
2993
2994
2995bool QXmlStreamReader::isStandaloneDocument()
const
2997 Q_D(
const QXmlStreamReader);
2998 return d->standalone;
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011bool QXmlStreamReader::hasStandaloneDeclaration()
const
3013 Q_D(
const QXmlStreamReader);
3014 return d->hasStandalone;
3018
3019
3020
3021
3022
3023
3024QStringView QXmlStreamReader::documentVersion()
const
3026 Q_D(
const QXmlStreamReader);
3027 if (d->type == QXmlStreamReader::StartDocument)
3028 return d->documentVersion;
3029 return QStringView();
3033
3034
3035
3036
3037
3038
3039QStringView QXmlStreamReader::documentEncoding()
const
3041 Q_D(
const QXmlStreamReader);
3042 if (d->type == QXmlStreamReader::StartDocument)
3043 return d->documentEncoding;
3044 return QStringView();
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
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
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3165#if QT_CONFIG(xmlstreamwriter)
3167class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3169 QXmlStreamWriter *q_ptr;
3170 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3172 enum class StartElementOption {
3174 OmitNamespaceDeclarations = 1,
3177 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3178 ~QXmlStreamWriterPrivate() {
3183 void raiseError(QXmlStreamWriter::Error error);
3184 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3185 void write(QAnyStringView s);
3186 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3187 bool finishStartElement(
bool contents =
true);
3188 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3189 StartElementOption option = StartElementOption::KeepEverything);
3190 QIODevice *device =
nullptr;
3191 QString *stringDevice =
nullptr;
3192 uint deleteDevice :1;
3193 uint inStartElement :1;
3194 uint inEmptyElement :1;
3195 uint lastWasStartElement :1;
3196 uint wroteSomething :1;
3197 uint autoFormatting :1;
3198 uint didWriteStartDocument :1;
3199 uint didWriteAnyToken :1;
3200 uint stopWritingOnError :1;
3201 std::string autoFormattingIndent = std::string(4,
' ');
3202 NamespaceDeclaration emptyNamespace;
3203 qsizetype lastNamespaceDeclaration = 1;
3204 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3205 QString errorString;
3207 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3208 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3209 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3211 int namespacePrefixCount = 0;
3213 void indent(
int level);
3215 void doWriteToDevice(QStringView s);
3216 void doWriteToDevice(QUtf8StringView s);
3217 void doWriteToDevice(QLatin1StringView s);
3221QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3222 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3223 inEmptyElement(
false), lastWasStartElement(
false),
3224 wroteSomething(
false), autoFormatting(
false),
3225 didWriteStartDocument(
false), didWriteAnyToken(
false),
3226 stopWritingOnError(
false)
3230void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3234 case QXmlStreamWriter::Error::IO:
3235 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3237 case QXmlStreamWriter::Error::Encoding:
3238 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3240 case QXmlStreamWriter::Error::InvalidCharacter:
3241 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3243 case QXmlStreamWriter::Error::Custom:
3244 errorString = QXmlStream::tr(
"An error occurred while writing");
3246 case QXmlStreamWriter::Error::None:
3247 errorString.clear();
3252void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3255 errorString = message.toString();
3258void QXmlStreamWriterPrivate::write(QAnyStringView s)
3260 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3263 if (error == QXmlStreamWriter::Error::IO)
3266 s.visit([&] (
auto s) { doWriteToDevice(s); });
3267 }
else if (stringDevice) {
3268 s.visit([&] (
auto s) { stringDevice->append(s); });
3270 qWarning(
"QXmlStreamWriter: No device");
3274void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3281 NextResult operator()(
const char *&it,
const char *)
const
3282 {
return {uchar(*it++),
false}; }
3285 NextResult operator()(
const char *&it,
const char *end)
const
3289 constexpr char32_t invalidValue = 0xFFFFFFFF;
3290 static_assert(invalidValue > QChar::LastValidCodePoint);
3291 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3292 const auto old_i = i;
3293 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3294 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3296 return result == invalidValue ? NextResult{U'\0',
true}
3297 : NextResult{result,
false};
3301 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3303 QStringIterator decoder(it, end);
3306 constexpr char32_t invalidValue = 0xFFFFFFFF;
3307 static_assert(invalidValue > QChar::LastValidCodePoint);
3308 char32_t result = decoder.next(invalidValue);
3309 it = decoder.position();
3310 return result == invalidValue ? NextResult{U'\0',
true}
3311 : NextResult{result,
false};
3316 escaped.reserve(s.size());
3317 s.visit([&] (
auto s) {
3318 using View =
decltype(s);
3319 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3320 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3322 auto it = s.begin();
3323 const auto end = s.end();
3327 QLatin1StringView replacement;
3332 const auto decoded = decoder(next_it, end);
3333 switch (decoded.value) {
3335 replacement =
"<"_L1;
3338 replacement =
">"_L1;
3341 replacement =
"&"_L1;
3344 replacement =
"""_L1;
3347 if (escapeWhitespace)
3348 replacement =
"	"_L1;
3351 if (escapeWhitespace)
3352 replacement =
" "_L1;
3355 if (escapeWhitespace)
3356 replacement =
" "_L1;
3360 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3361 if (stopWritingOnError)
3363 replacement =
""_L1;
3364 Q_ASSERT(!replacement.isNull());
3367 if (decoded.value > 0x1F)
3373 raiseError(decoded.encodingError
3374 ? QXmlStreamWriter::Error::Encoding
3375 : QXmlStreamWriter::Error::InvalidCharacter);
3376 if (stopWritingOnError)
3378 replacement =
""_L1;
3379 Q_ASSERT(!replacement.isNull());
3382 if (!replacement.isNull())
3387 escaped.append(View{mark, it});
3388 escaped.append(replacement);
3397void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3398 if (namespaceDeclaration.prefix.isEmpty()) {
3400 write(namespaceDeclaration.namespaceUri);
3404 write(namespaceDeclaration.prefix);
3406 write(namespaceDeclaration.namespaceUri);
3409 didWriteAnyToken =
true;
3412bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3414 bool hadSomethingWritten = wroteSomething;
3415 wroteSomething = contents;
3416 if (!inStartElement)
3417 return hadSomethingWritten;
3419 if (inEmptyElement) {
3421 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3422 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3423 lastWasStartElement =
false;
3427 inStartElement = inEmptyElement =
false;
3428 lastNamespaceDeclaration = namespaceDeclarations.size();
3429 didWriteAnyToken =
true;
3430 return hadSomethingWritten;
3433QXmlStreamPrivateTagStack::NamespaceDeclaration &
3434QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3436 const bool prefixIsXml = prefix ==
"xml"_L1;
3437 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3438 if (prefixIsXml && !namespaceUriIsXml) {
3439 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3440 "than 'http://www.w3.org/XML/1998/namespace'");
3441 }
else if (!prefixIsXml && namespaceUriIsXml) {
3442 const QString prefixString = prefix.toString();
3443 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3444 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3445 qUtf16Printable(prefixString));
3447 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3448 const QString prefixString = prefix.toString();
3449 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3450 "'http://www.w3.org/2000/xmlns/'",
3451 qUtf16Printable(prefixString));
3453 auto &namespaceDeclaration = namespaceDeclarations.push();
3454 namespaceDeclaration.prefix = addToStringStorage(prefix);
3455 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3456 return namespaceDeclaration;
3459QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3461 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3462 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3463 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3464 return namespaceDeclaration;
3467 if (namespaceUri.isEmpty())
3468 return emptyNamespace;
3469 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3470 if (namespaceUri.isEmpty()) {
3471 namespaceDeclaration.prefix.clear();
3474 int n = ++namespacePrefixCount;
3476 s = u'n' + QString::number(n++);
3477 qsizetype j = namespaceDeclarations.size() - 2;
3478 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3483 namespaceDeclaration.prefix = addToStringStorage(s);
3485 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3486 if (writeDeclaration)
3487 writeNamespaceDeclaration(namespaceDeclaration);
3488 return namespaceDeclaration;
3493void QXmlStreamWriterPrivate::indent(
int level)
3495 if (didWriteStartDocument || didWriteAnyToken)
3497 for (
int i = 0; i < level; ++i)
3498 write(autoFormattingIndent);
3501void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3503 constexpr qsizetype MaxChunkSize = 512;
3504 char buffer [3 * MaxChunkSize];
3505 QStringEncoder::State state;
3506 while (!s.isEmpty()) {
3507 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3508 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3509 doWriteToDevice(QUtf8StringView{buffer, end});
3510 s = s.sliced(chunkSize);
3512 if (state.remainingChars > 0)
3513 raiseError(QXmlStreamWriter::Error::Encoding);
3516void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3518 QByteArrayView bytes = s;
3519 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3520 raiseError(QXmlStreamWriter::Error::IO);
3523void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3525 constexpr qsizetype MaxChunkSize = 512;
3526 char buffer [2 * MaxChunkSize];
3527 while (!s.isEmpty()) {
3528 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3529 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3530 doWriteToDevice(QUtf8StringView{buffer, end});
3531 s = s.sliced(chunkSize);
3536
3537
3538
3539
3540QXmlStreamWriter::QXmlStreamWriter()
3541 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3546
3547
3548QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3549 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3551 Q_D(QXmlStreamWriter);
3556
3557
3558
3559QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3560 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3562 Q_D(QXmlStreamWriter);
3563 d->device =
new QBuffer(array);
3564 d->device->open(QIODevice::WriteOnly);
3565 d->deleteDevice =
true;
3570
3571QXmlStreamWriter::QXmlStreamWriter(QString *string)
3572 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3574 Q_D(QXmlStreamWriter);
3575 d->stringDevice = string;
3579
3580
3581QXmlStreamWriter::~QXmlStreamWriter()
3587
3588
3589
3590
3591
3592void QXmlStreamWriter::setDevice(QIODevice *device)
3594 Q_D(QXmlStreamWriter);
3595 if (device == d->device)
3597 d->stringDevice =
nullptr;
3598 if (d->deleteDevice) {
3600 d->deleteDevice =
false;
3606
3607
3608
3609
3610
3611QIODevice *QXmlStreamWriter::device()
const
3613 Q_D(
const QXmlStreamWriter);
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3634
3635
3636
3637
3638
3639
3640
3641void QXmlStreamWriter::setAutoFormatting(
bool enable)
3643 Q_D(QXmlStreamWriter);
3644 d->autoFormatting = enable;
3648
3649
3650
3651
3652bool QXmlStreamWriter::autoFormatting()
const
3654 Q_D(
const QXmlStreamWriter);
3655 return d->autoFormatting;
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3672void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3674 Q_D(QXmlStreamWriter);
3675 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3678int QXmlStreamWriter::autoFormattingIndent()
const
3680 Q_D(
const QXmlStreamWriter);
3681 const QLatin1StringView indent(d->autoFormattingIndent);
3682 return indent.count(u' ') - indent.count(u'\t');
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702bool QXmlStreamWriter::stopWritingOnError()
const
3704 Q_D(
const QXmlStreamWriter);
3705 return d->stopWritingOnError;
3708void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3710 Q_D(QXmlStreamWriter);
3711 d->stopWritingOnError = stop;
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726bool QXmlStreamWriter::hasError()
const
3728 return error() != QXmlStreamWriter::Error::None;
3732
3733
3734
3735
3736
3737
3738
3739
3740QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3742 Q_D(
const QXmlStreamWriter);
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756QString QXmlStreamWriter::errorString()
const
3758 Q_D(
const QXmlStreamWriter);
3759 return d->errorString;
3763
3764
3765
3766
3767
3768
3769
3770
3771void QXmlStreamWriter::raiseError(QAnyStringView message)
3773 Q_D(QXmlStreamWriter);
3774 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3790 Q_D(QXmlStreamWriter);
3791 Q_ASSERT(d->inStartElement);
3792 Q_ASSERT(count(qualifiedName,
':') <= 1);
3794 d->write(qualifiedName);
3796 d->writeEscaped(value,
true);
3798 d->didWriteAnyToken =
true;
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3814 Q_D(QXmlStreamWriter);
3815 Q_ASSERT(d->inStartElement);
3816 Q_ASSERT(!contains(name,
':'));
3817 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3819 if (!namespaceDeclaration.prefix.isEmpty()) {
3820 d->write(namespaceDeclaration.prefix);
3825 d->writeEscaped(value,
true);
3827 d->didWriteAnyToken =
true;
3831
3832
3833
3834
3835
3836
3837
3838void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3840 if (attribute.namespaceUri().isEmpty())
3841 writeAttribute(attribute.qualifiedName(), attribute.value());
3843 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3848
3849
3850
3851
3852
3853
3854
3855
3856void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3858 Q_D(QXmlStreamWriter);
3859 Q_ASSERT(d->inStartElement);
3861 for (
const auto &attr : attributes)
3862 writeAttribute(attr);
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3879 Q_D(QXmlStreamWriter);
3880 d->finishStartElement();
3881 d->write(
"<![CDATA[");
3882 while (!text.isEmpty()) {
3883 const auto idx = indexOf(text,
"]]>"_L1);
3886 d->write(text.first(idx));
3890 text = text.sliced(idx + 3);
3898
3899
3900
3901
3902
3903
3904
3905
3906void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3908 Q_D(QXmlStreamWriter);
3909 d->finishStartElement();
3910 d->writeEscaped(text);
3915
3916
3917
3918
3919
3920
3921void QXmlStreamWriter::writeComment(QAnyStringView text)
3923 Q_D(QXmlStreamWriter);
3924 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
3925 if (!d->finishStartElement(
false) && d->autoFormatting)
3926 d->indent(d->tagStack.size());
3930 d->inStartElement = d->lastWasStartElement =
false;
3935
3936
3937
3938
3939
3940void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
3942 Q_D(QXmlStreamWriter);
3943 d->finishStartElement();
3944 if (d->autoFormatting)
3947 if (d->autoFormatting)
3954
3955
3956
3957
3958
3959
3960void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
3962 Q_D(QXmlStreamWriter);
3963 Q_ASSERT(count(qualifiedName,
':') <= 1);
3964 d->writeStartElement({}, qualifiedName);
3965 d->inEmptyElement =
true;
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
3981 Q_D(QXmlStreamWriter);
3982 Q_ASSERT(!contains(name,
':'));
3983 d->writeStartElement(namespaceUri, name);
3984 d->inEmptyElement =
true;
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
4000 writeStartElement(qualifiedName);
4001 writeCharacters(text);
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
4019 writeStartElement(namespaceUri, name);
4020 writeCharacters(text);
4026
4027
4028
4029
4030void QXmlStreamWriter::writeEndDocument()
4032 Q_D(QXmlStreamWriter);
4033 while (d->tagStack.size())
4035 if (d->didWriteStartDocument || d->didWriteAnyToken)
4040
4041
4042
4043
4044void QXmlStreamWriter::writeEndElement()
4046 Q_D(QXmlStreamWriter);
4047 Q_ASSERT(d->didWriteAnyToken);
4048 if (d->tagStack.isEmpty())
4052 if (d->inStartElement && !d->inEmptyElement) {
4054 d->lastWasStartElement = d->inStartElement =
false;
4055 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4056 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4060 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4061 d->indent(d->tagStack.size()-1);
4062 if (d->tagStack.isEmpty())
4064 d->lastWasStartElement =
false;
4065 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4066 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4068 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4069 d->write(tag.namespaceDeclaration.prefix);
4079
4080
4081
4082
4083
4084void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4086 Q_D(QXmlStreamWriter);
4087 d->finishStartElement();
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4113 Q_D(QXmlStreamWriter);
4114 Q_ASSERT(prefix !=
"xmlns"_L1);
4115 if (prefix.isEmpty()) {
4116 d->findNamespace(namespaceUri, d->inStartElement);
4118 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4119 if (d->inStartElement)
4120 d->writeNamespaceDeclaration(namespaceDeclaration);
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4140 Q_D(QXmlStreamWriter);
4141 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4142 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4143 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4144 namespaceDeclaration.prefix.clear();
4145 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4146 if (d->inStartElement)
4147 d->writeNamespaceDeclaration(namespaceDeclaration);
4152
4153
4154
4155
4156
4157
4158void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4160 Q_D(QXmlStreamWriter);
4161 Q_ASSERT(!contains(data,
"?>"_L1));
4162 if (!d->finishStartElement(
false) && d->autoFormatting)
4163 d->indent(d->tagStack.size());
4166 if (!data.isNull()) {
4171 d->didWriteAnyToken =
true;
4177
4178
4179
4180
4181
4182
4183void QXmlStreamWriter::writeStartDocument()
4185 writeStartDocument(
"1.0"_L1);
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4207 Q_D(QXmlStreamWriter);
4208 d->finishStartElement(
false);
4209 d->write(
"<?xml version=\"");
4212 d->write(
"\" encoding=\"UTF-8");
4214 d->didWriteStartDocument =
true;
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4237 Q_D(QXmlStreamWriter);
4238 d->finishStartElement(
false);
4239 d->write(
"<?xml version=\"");
4242 d->write(
"\" encoding=\"UTF-8");
4244 d->write(
"\" standalone=\"yes\"?>");
4246 d->write(
"\" standalone=\"no\"?>");
4247 d->didWriteStartDocument =
true;
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4263 Q_D(QXmlStreamWriter);
4264 Q_ASSERT(count(qualifiedName,
':') <= 1);
4265 d->writeStartElement({}, qualifiedName);
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4282 Q_D(QXmlStreamWriter);
4283 Q_ASSERT(!contains(name,
':'));
4284 d->writeStartElement(namespaceUri, name);
4287void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4288 StartElementOption option)
4290 if (!finishStartElement(
false) && autoFormatting)
4291 indent(tagStack.size());
4293 Tag &tag = tagStack_push();
4294 tag.name = addToStringStorage(name);
4295 tag.namespaceDeclaration = findNamespace(namespaceUri);
4297 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4298 write(tag.namespaceDeclaration.prefix);
4302 inStartElement = lastWasStartElement =
true;
4304 if (option != StartElementOption::OmitNamespaceDeclarations) {
4305 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4306 writeNamespaceDeclaration(namespaceDeclarations[i]);
4308 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4309 didWriteAnyToken =
true;
4312#if QT_CONFIG(xmlstreamreader)
4314
4315
4316
4317
4318
4319
4320void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4322 Q_D(QXmlStreamWriter);
4323 switch (reader.tokenType()) {
4324 case QXmlStreamReader::NoToken:
4326 case QXmlStreamReader::StartDocument:
4327 writeStartDocument();
4329 case QXmlStreamReader::EndDocument:
4332 case QXmlStreamReader::StartElement: {
4334 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4335 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4336 for (
const auto &namespaceDeclaration : nsDeclarations) {
4337 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4338 namespaceDeclaration.prefix());
4339 extraNamespaces.append(extraNamespace);
4341 d->writeStartElement(
4342 reader.namespaceUri(), reader.name(),
4343 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4345 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4346 d->writeNamespaceDeclaration(extraNamespace);
4347 writeAttributes(reader.attributes());
4349 case QXmlStreamReader::EndElement:
4352 case QXmlStreamReader::Characters:
4353 if (reader.isCDATA())
4354 writeCDATA(reader.text());
4356 writeCharacters(reader.text());
4358 case QXmlStreamReader::Comment:
4359 writeComment(reader.text());
4361 case QXmlStreamReader::DTD:
4362 writeDTD(reader.text());
4364 case QXmlStreamReader::EntityReference:
4365 writeEntityReference(reader.name());
4367 case QXmlStreamReader::ProcessingInstruction:
4368 writeProcessingInstruction(reader.processingInstructionTarget(),
4369 reader.processingInstructionData());
4372 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4373 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4380#if QT_CONFIG(xmlstreamreader)
4381static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4382 QXmlStreamReaderPrivate::XmlContext ctxt)
4385 case QXmlStreamReader::StartDocument:
4386 case QXmlStreamReader::DTD:
4387 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4389 case QXmlStreamReader::StartElement:
4390 case QXmlStreamReader::EndElement:
4391 case QXmlStreamReader::Characters:
4392 case QXmlStreamReader::EntityReference:
4393 case QXmlStreamReader::EndDocument:
4394 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4396 case QXmlStreamReader::Comment:
4397 case QXmlStreamReader::ProcessingInstruction:
4400 case QXmlStreamReader::NoToken:
4401 case QXmlStreamReader::Invalid:
4406#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4407 Q_UNREACHABLE_RETURN(
false);
4414
4415
4416
4417
4418
4419
4420bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4423 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4427 const bool result = isTokenAllowedInContext(type, currentContext);
4428 if (result || currentContext == XmlContext::Body)
4432 currentContext = XmlContext::Body;
4433 return isTokenAllowedInContext(type, currentContext);
4437
4438
4439
4440
4441void QXmlStreamReaderPrivate::checkToken()
4443 Q_Q(QXmlStreamReader);
4446 const XmlContext context = currentContext;
4447 const bool ok = isValidToken(type);
4450 if (error != QXmlStreamReader::Error::NoError)
4454 raiseError(QXmlStreamReader::UnexpectedElementError,
4455 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4456 .arg(q->tokenString(), contextString(context)));
4460 if (type != QXmlStreamReader::DTD)
4465 raiseError(QXmlStreamReader::UnexpectedElementError,
4466 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4487
4488
4489
4490
4491
4492
4493
4494