5#include "QtCore/qxmlstream.h"
7#if QT_CONFIG(xmlstream)
9#include "qxmlutils_p.h"
14#include <QtCore/qspan.h>
15#include <qstringconverter.h>
18#include <qscopeguard.h>
19#include <qcoreapplication.h>
20#include <QtCore/private/qduplicatetracker_p.h>
21#include <private/qoffsetstringarray_p.h>
22#include <private/qtools_p.h>
25#include "qxmlstream_p.h"
26#include "qxmlstreamparser_p.h"
27#include <private/qstringconverter_p.h>
28#include <private/qstringiterator_p.h>
34using namespace QtPrivate;
35using namespace Qt::StringLiterals;
36using namespace QtMiscUtils;
38constexpr uint StreamEOF = ~0U;
41template <
typename Range>
42auto reversed(Range &r)
46 auto begin() {
return std::make_reverse_iterator(std::end(*r)); }
47 auto end() {
return std::make_reverse_iterator(std::begin(*r)); }
53template <
typename Range>
54void reversed(
const Range &&) =
delete;
57auto transform(QLatin1StringView haystack,
char needle)
59 struct R { QLatin1StringView haystack;
char16_t needle; };
60 return R{haystack, uchar(needle)};
63auto transform(QStringView haystack,
char needle)
65 struct R { QStringView haystack;
char16_t needle; };
66 return R{haystack, uchar(needle)};
69auto transform(QUtf8StringView haystack,
char needle)
71 struct R { QByteArrayView haystack;
char needle; };
72 return R{haystack, needle};
75auto transform(QLatin1StringView haystack, QLatin1StringView needle)
77 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
78 return R{haystack, needle};
81auto transform(QStringView haystack, QLatin1StringView needle)
83 struct R { QStringView haystack; QLatin1StringView needle; };
84 return R{haystack, needle};
87auto transform(QUtf8StringView haystack, QLatin1StringView needle)
89 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
90 return R{QLatin1StringView{QByteArrayView{haystack}}, needle};
93#define WRAP(method, Needle)
94 auto method (QAnyStringView s, Needle needle) noexcept
96 return s.visit([needle](auto s) {
97 auto r = transform(s, needle);
98 return r.haystack. method (r.needle);
105WRAP(contains, QLatin1StringView)
107WRAP(indexOf, QLatin1StringView)
110template <
auto V>
struct Value {
static constexpr auto value = V; };
111template <
typename T>
struct EncodingForHelper;
112template <>
struct EncodingForHelper<QStringView> : Value<QStringDecoder::Utf16> {};
113template <>
struct EncodingForHelper<QLatin1StringView> : Value<QStringDecoder::Latin1> {};
114template <
bool B>
struct EncodingForHelper<QBasicUtf8StringView<B>> : Value<QStringDecoder::Utf8> {};
116constexpr auto encodingFor = EncodingForHelper<T>::value;
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
171
172
173
174
175
176
177
178
179
180
181
182
183
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
268
269
270QXmlStreamEntityResolver::~QXmlStreamEntityResolver()
275
276
277
278
279QString QXmlStreamEntityResolver::resolveEntity(
const QString& ,
const QString& )
287
288
289
290
291
292
293
294
296QString QXmlStreamEntityResolver::resolveUndeclaredEntity(
const QString &)
301#if QT_CONFIG(xmlstreamreader)
303QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(
const QString &name)
306 return entityResolver->resolveUndeclaredEntity(name);
313
314
315
316
317
318
319
320
321
322
323
324void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
326 Q_D(QXmlStreamReader);
327 d->entityResolver = resolver;
331
332
333
334
335
336
337QXmlStreamEntityResolver *QXmlStreamReader::entityResolver()
const
339 Q_D(
const QXmlStreamReader);
340 return d->entityResolver;
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
476
477
478
479
480
481
482
483
484
485
486
487
488
489
492static void warn_addData_with_device()
494 qWarning(
"QXmlStreamReader: addData() with device()");
498
499
500
501
502QXmlStreamReader::QXmlStreamReader()
503 : d_ptr(
new QXmlStreamReaderPrivate(
this))
508
509
510
511QXmlStreamReader::QXmlStreamReader(QIODevice *device)
512 : d_ptr(
new QXmlStreamReaderPrivate(
this))
518
519
520
521
522
523
524
525
528
529
530
531
532
533
534
535
536
537void QXmlStreamReaderPrivate::appendDataWithEncoding(
const QByteArray &data,
538 QStringDecoder::Encoding enc)
540 if (tryAppendViewWithEncoding(data, enc))
542 dataInfo.emplace_back(data, enc);
545bool QXmlStreamReaderPrivate::tryAppendViewWithEncoding(QByteArrayView data, QStringDecoder::Encoding enc)
551 if (!dataInfo.empty()) {
552 auto &last = dataInfo.back();
553 if (last.encoding == enc) {
554 last.buffer.append(data);
561void QXmlStreamReaderPrivate::appendViewWithEncoding(QByteArrayView data, QStringDecoder::Encoding enc)
563 if (tryAppendViewWithEncoding(data, enc))
565 dataInfo.emplace_back(data.toByteArray(), enc);
569
570
571
572
573
574
575
576QXmlStreamReader::QXmlStreamReader(QAnyStringView data)
577 : d_ptr(
new QXmlStreamReaderPrivate(
this))
583
584
585
586
587
588QXmlStreamReader::QXmlStreamReader(
const QByteArray &data, PrivateConstructorTag)
589 : d_ptr(
new QXmlStreamReaderPrivate(
this))
591 Q_D(QXmlStreamReader);
592 d->appendDataWithEncoding(data, QStringDecoder::System);
596
597
598QXmlStreamReader::~QXmlStreamReader()
600 Q_D(QXmlStreamReader);
606
607
608
609
612
613
614
615
616
617void QXmlStreamReader::setDevice(QIODevice *device)
619 Q_D(QXmlStreamReader);
620 if (d->deleteDevice) {
622 d->deleteDevice =
false;
630
631
632
633
634
635QIODevice *QXmlStreamReader::device()
const
637 Q_D(
const QXmlStreamReader);
642
643
644
645
646
647
648
649
650
652static bool isDecoderForEncoding(
const QStringDecoder &dec, QStringDecoder::Encoding enc)
657 const auto decName = dec.name();
658 if (!decName || !*decName)
661 const auto encName = QStringConverter::nameForEncoding(enc);
662 return encName && strcmp(decName, encName) == 0;
666
667
668
669
670
671
672
673
674void QXmlStreamReader::addData(QAnyStringView data)
676 Q_D(QXmlStreamReader);
678 return warn_addData_with_device();
679 data.visit([d](
auto data) {
680 d->appendViewWithEncoding(as_bytes(QSpan(data)), encodingFor<
decltype(data)>);
685
686
687
688
689
690void QXmlStreamReader::addDataImpl(
const QByteArray &data)
692 Q_D(QXmlStreamReader);
694 return warn_addData_with_device();
695 d->appendDataWithEncoding(data, QStringDecoder::System);
699
700
701
702
703
704void QXmlStreamReader::clear()
706 Q_D(QXmlStreamReader);
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730bool QXmlStreamReader::atEnd()
const
732 Q_D(
const QXmlStreamReader);
734 && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError)
735 || (d->type == QXmlStreamReader::EndDocument))) {
737 return d->device->atEnd();
739 return d->dataInfo.empty();
741 return (d->atEnd || d->type == QXmlStreamReader::Invalid);
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763QXmlStreamReader::TokenType QXmlStreamReader::readNext()
765 Q_D(QXmlStreamReader);
766 if (d->type != Invalid) {
767 if (!d->hasCheckedStartDocument)
768 if (!d->checkStartDocument())
771 if (d->atEnd && d->type != EndDocument && d->type != Invalid)
772 d->raiseError(PrematureEndOfDocumentError);
773 else if (!d->atEnd && d->type == EndDocument)
774 d->raiseWellFormedError(QXmlStream::tr(
"Extra content at end of document."));
775 }
else if (d->error == PrematureEndOfDocumentError) {
788
789
790
791
792
793
794
795
796
797QXmlStreamReader::TokenType QXmlStreamReader::tokenType()
const
799 Q_D(
const QXmlStreamReader);
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820bool QXmlStreamReader::readNextStartElement()
822 while (readNext() != Invalid) {
823 if (isEndElement() || isEndDocument())
825 else if (isStartElement())
832
833
834
835
836
837
838
839
840
841
842void QXmlStreamReader::skipCurrentElement()
845 while (depth && readNext() != Invalid) {
848 else if (isStartElement())
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872QString QXmlStreamReader::readRawInnerData()
874 Q_D(QXmlStreamReader);
877 auto specialToEntities = [](QStringView text, QString &output) {
879 QLatin1StringView replacement;
880 const qsizetype sz = text.size();
881 for (qsizetype i = 0; i < sz; ++i) {
882 switch (text[i].unicode()) {
884 replacement =
"<"_L1;
887 replacement =
">"_L1;
890 replacement =
"&"_L1;
893 replacement =
"""_L1;
896 replacement =
"'"_L1;
902 output += text.mid(chunk, i - chunk);
903 output += replacement;
906 if (chunk < text.size())
907 output += text.mid(chunk);
910 if (isStartElement()) {
912 while (!atEnd() && depth) {
913 switch (readNext()) {
915 raw +=
'<'_L1 + name();
916 const QXmlStreamAttributes attrs = attributes();
917 for (
auto it = attrs.begin(); it != attrs.end(); ++it) {
918 raw +=
' '_L1 + it->name() +
"=\""_L1;
919 specialToEntities(it->value(), raw);
929 raw +=
"</"_L1 + name() +
'>'_L1;
933 raw +=
"<![CDATA["_L1 + text() +
"]]>"_L1;
935 specialToEntities(text(), raw);
938 raw +=
"<!--"_L1 + text() +
"-->"_L1;
940 case EntityReference:
941 raw +=
'&'_L1 + name() +
';'_L1;
943 case ProcessingInstruction:
944 raw +=
"<?"_L1 + processingInstructionTarget()
945 +
' '_L1 + processingInstructionData()
951 d->raiseError(NotWellFormedError,
952 QXmlStream::tr(
"Unexpected token while "
953 "reading raw inner data."));
962static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
973 "ProcessingInstruction"
976static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
982
983
984
985
986
987
988
989
990
993void QXmlStreamReader::setNamespaceProcessing(
bool enable)
995 Q_D(QXmlStreamReader);
996 d->namespaceProcessing = enable;
999bool QXmlStreamReader::namespaceProcessing()
const
1001 Q_D(
const QXmlStreamReader);
1002 return d->namespaceProcessing;
1006
1007
1008
1009QString QXmlStreamReader::tokenString()
const
1011 Q_D(
const QXmlStreamReader);
1012 return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
1016
1017
1018
1019static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
1021 return QLatin1StringView(QXmlStreamReader_XmlContextString.viewAt(
static_cast<
int>(ctxt)));
1026QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
1028 tagStack.reserve(16);
1029 tagStackStringStorageSize = 0;
1030 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1031 namespaceDeclaration.namespaceUri = addToStringStorage(u"http://www.w3.org/XML/1998/namespace");
1032 namespaceDeclaration.prefix = addToStringStorage(u"xml");
1033 initialTagStackStringStorageSize = tagStackStringStorageSize;
1037#if QT_CONFIG(xmlstreamreader)
1039QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
1043 deleteDevice =
false;
1045 sym_stack =
nullptr;
1046 state_stack =
nullptr;
1048 entityResolver =
nullptr;
1052void QXmlStreamReaderPrivate::init()
1055#define ADD_PREDEFINED(n, v)
1057 Entity e = Entity::createLiteral(n##_L1, v##_L1);
1058 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e));
1060 ADD_PREDEFINED(
"lt",
"<");
1061 ADD_PREDEFINED(
"gt",
">");
1062 ADD_PREDEFINED(
"amp",
"&");
1063 ADD_PREDEFINED(
"apos",
"'");
1064 ADD_PREDEFINED(
"quot",
"\"");
1065#undef ADD_PREDEFINED
1066 parameterEntityHash.clear();
1068 lastAttributeIsCData =
false;
1071 isEmptyElement =
false;
1072 isWhitespace =
true;
1075 hasStandalone =
false;
1077 resumeReduction = 0;
1078 state_stack[tos++] = 0;
1079 state_stack[tos] = 0;
1081 putStack.reserve(32);
1083 textBuffer.reserve(256);
1087 attributes.reserve(16);
1088 lineNumber = lastLineStart = characterOffset = 0;
1091 decoder = QStringDecoder();
1092 attributeStack.clear();
1093 attributeStack.reserve(16);
1094 entityReferenceStack.clear();
1095 entityReferenceStack.reserve(16);
1097 entityParser.reset();
1098 hasCheckedStartDocument =
false;
1099 normalizeLiterals =
false;
1102 inParseEntity =
false;
1103 referenceToUnparsedEntityDetected =
false;
1104 referenceToParameterEntityDetected =
false;
1105 hasExternalDtdSubset =
false;
1106 lockEncoding =
false;
1107 namespaceProcessing =
true;
1108 rawReadBuffer.clear();
1109 chunkDecoder = QStringDecoder();
1112 tagStackStringStorageSize = initialTagStackStringStorageSize;
1114 type = QXmlStreamReader::NoToken;
1115 error = QXmlStreamReader::NoError;
1116 currentContext = XmlContext::Prolog;
1121
1122
1123
1124void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1126 Q_Q(QXmlStreamReader);
1128 if (value.isEmpty())
1133 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1135 entityParser->init();
1136 entityParser->inParseEntity =
true;
1137 entityParser->readBuffer = value;
1138 entityParser->injectToken(PARSE_ENTITY);
1139 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1140 entityParser->parse();
1141 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1142 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1146inline void QXmlStreamReaderPrivate::reallocateStack()
1151 const auto newStackSize = stack_size * 2;
1153 void *p = qt_reallocarray(sym_stack, size_t(newStackSize),
sizeof(Value));
1155 sym_stack =
static_cast<Value*>(p);
1156 p = qt_reallocarray(state_stack, size_t(newStackSize),
sizeof(
int));
1158 state_stack =
static_cast<
int*>(p);
1161 stack_size = newStackSize;
1165QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1172inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1174 uint peekc = peekChar();
1175 if (peekc ==
'\n') {
1176 if (putStack.size())
1182 if (peekc == StreamEOF) {
1190
1191
1192
1193inline uint QXmlStreamReaderPrivate::getChar()
1196 if (putStack.size()) {
1197 c = atEnd ? StreamEOF : putStack.pop();
1199 if (readBufferPos < readBuffer.size())
1200 c = readBuffer.at(readBufferPos++).unicode();
1202 c = getChar_helper();
1208inline uint QXmlStreamReaderPrivate::peekChar()
1211 if (putStack.size()) {
1213 }
else if (readBufferPos < readBuffer.size()) {
1214 c = readBuffer.at(readBufferPos).unicode();
1216 if ((c = getChar_helper()) != StreamEOF)
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1237 const qsizetype pos = textBuffer.size();
1238 const auto oldLineNumber = lineNumber;
1241 while ((c = getChar()) != StreamEOF) {
1245 if ((c = filterCarriageReturn()) == 0)
1250 lastLineStart = characterOffset + readBufferPos;
1253 textBuffer += QChar(c);
1256 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1257 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1258 lineNumber = oldLineNumber;
1261 textBuffer += QChar(c);
1266 if (c == uint(*str)) {
1268 if (tokenToInject >= 0)
1269 injectToken(tokenToInject);
1272 if (scanString(str + 1, tokenToInject,
false))
1277 putString(textBuffer, pos);
1278 textBuffer.resize(pos);
1279 lineNumber = oldLineNumber;
1283bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1288 if (c != ushort(str[n])) {
1292 putChar(ushort(str[n]));
1298 textBuffer += QLatin1StringView(str, n);
1300 const qsizetype s = fastScanSpace();
1302 qsizetype pos = textBuffer.size() - n - s;
1303 putString(textBuffer, pos);
1304 textBuffer.resize(pos);
1308 if (tokenToInject >= 0)
1309 injectToken(tokenToInject);
1313bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1315 switch (peekChar()) {
1317 return scanString(spell[CDATA_START], CDATA_START,
false);
1319 return scanString(spell[DOCTYPE], DOCTYPE);
1321 return scanString(spell[ATTLIST], ATTLIST);
1323 return scanString(spell[NOTATION], NOTATION);
1325 if (scanString(spell[ELEMENT], ELEMENT))
1327 return scanString(spell[ENTITY], ENTITY);
1335bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1337 switch (peekChar()) {
1339 return scanString(spell[SYSTEM], SYSTEM);
1341 return scanString(spell[PUBLIC], PUBLIC);
1348bool QXmlStreamReaderPrivate::scanNData()
1350 if (fastScanSpace()) {
1351 if (scanString(spell[NDATA], NDATA))
1358bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1360 switch (peekChar()) {
1362 return scanString(spell[REQUIRED], REQUIRED,
false);
1364 return scanString(spell[IMPLIED], IMPLIED,
false);
1366 return scanString(spell[FIXED], FIXED,
false);
1373bool QXmlStreamReaderPrivate::scanAttType()
1375 switch (peekChar()) {
1377 return scanString(spell[CDATA], CDATA);
1379 if (scanString(spell[ID], ID))
1381 if (scanString(spell[IDREF], IDREF))
1383 return scanString(spell[IDREFS], IDREFS);
1385 if (scanString(spell[ENTITY], ENTITY))
1387 return scanString(spell[ENTITIES], ENTITIES);
1389 if (scanString(spell[NOTATION], NOTATION))
1391 if (scanString(spell[NMTOKEN], NMTOKEN))
1393 return scanString(spell[NMTOKENS], NMTOKENS);
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1416 while ((c = getChar()) != StreamEOF) {
1417 switch (ushort(c)) {
1422
1426 if (filterCarriageReturn() == 0)
1431 lastLineStart = characterOffset + readBufferPos;
1435 if (normalizeLiterals)
1438 textBuffer += QChar(c);
1445 if (!(c & 0xff0000)) {
1455 textBuffer += QChar(ushort(c));
1462inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1466 while ((c = getChar()) != StreamEOF) {
1469 if ((c = filterCarriageReturn()) == 0)
1474 lastLineStart = characterOffset + readBufferPos;
1478 textBuffer += QChar(c);
1490
1491
1492
1493
1494
1495inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1499 while ((c = getChar()) != StreamEOF) {
1500 switch (ushort(c)) {
1507 isWhitespace =
false;
1508 const qsizetype pos = textBuffer.size();
1509 textBuffer += QChar(ushort(c));
1511 while ((c = getChar()) ==
']') {
1512 textBuffer += QChar(ushort(c));
1515 if (c == StreamEOF) {
1516 putString(textBuffer, pos);
1517 textBuffer.resize(pos);
1518 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1519 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1527 if ((c = filterCarriageReturn()) == 0)
1532 lastLineStart = characterOffset + readBufferPos;
1536 textBuffer += QChar(ushort(c));
1541 if (!(c & 0xff0000)) {
1551 isWhitespace =
false;
1552 textBuffer += QChar(ushort(c));
1560inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1564 while ((c = getChar()) != StreamEOF) {
1568 raiseNamePrefixTooLongError();
1569 return std::nullopt;
1598 if (val && val->prefix == n + 1) {
1606 if (val->prefix == 0) {
1607 val->prefix = qint16(n + 2);
1618 textBuffer += QChar(ushort(c));
1625 qsizetype pos = textBuffer.size() - n;
1626 putString(textBuffer, pos);
1627 textBuffer.resize(pos);
1631enum NameChar { NameBeginning, NameNotBeginning, NotName };
1633static const char Begi =
static_cast<
char>(NameBeginning);
1634static const char NtBg =
static_cast<
char>(NameNotBeginning);
1635static const char NotN =
static_cast<
char>(NotName);
1637static const char nameCharTable[128] =
1640 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1641 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1643 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1644 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1646 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1647 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1649 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1650 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1652 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1653 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1655 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1656 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1658 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1659 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1661 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1662 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1665static inline NameChar fastDetermineNameChar(QChar ch)
1667 ushort uc = ch.unicode();
1669 return static_cast<NameChar>(nameCharTable[uc]);
1671 QChar::Category cat = ch.category();
1673 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1674 || cat == QChar::Number_Letter)
1675 return NameBeginning;
1676 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1677 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1678 return NameNotBeginning;
1682inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1686 while ((c = getChar()) != StreamEOF) {
1687 if (fastDetermineNameChar(QChar(c)) == NotName) {
1692 textBuffer += QChar(c);
1696 qsizetype pos = textBuffer.size() - n;
1697 putString(textBuffer, pos);
1698 textBuffer.resize(pos);
1703void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1706 putString(s.mid(from));
1709 putStack.reserve(s.size());
1710 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1711 putStack.rawPush() = it->unicode();
1714void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1716 putStack.reserve(s.size());
1717 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1718 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1721void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1723 putStack.reserve(s.size());
1724 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1725 char16_t c = it->unicode();
1726 if (c ==
'\n' || c ==
'\r')
1727 putStack.rawPush() = ((LETTER << 16) | c);
1729 putStack.rawPush() = c;
1732void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1734 putStack.reserve(s.size());
1735 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1736 char16_t c = it->unicode();
1737 if (c ==
'&' || c ==
';')
1738 putStack.rawPush() = c;
1739 else if (c ==
'\n' || c ==
'\r')
1740 putStack.rawPush() =
' ';
1742 putStack.rawPush() = ((LETTER << 16) | c);
1746uint QXmlStreamReaderPrivate::getChar_helper()
1748 constexpr qsizetype BUFFER_SIZE = 8192;
1749 characterOffset += readBufferPos;
1751 if (readBuffer.size())
1752 readBuffer.resize(0);
1753 if (decoder.isValid())
1756 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1757 if (!decoder.isValid()) {
1759 if (nbytesread < 4) {
1763 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1765 encoding = QStringDecoder::Utf8;
1766 decoder = QStringDecoder(*encoding);
1769 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1771 if (lockEncoding && decoder.hasError()) {
1780 rawReadBuffer.resize(BUFFER_SIZE);
1781 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1782 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1789 if (!tryDecodeWithGlobalDecoder())
1791 }
else if (dataInfo.empty()) {
1795 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1802 if (bufAndEnc.encoding == QStringDecoder::System) {
1804 rawReadBuffer += bufAndEnc.buffer;
1806 rawReadBuffer = bufAndEnc.buffer;
1807 nbytesread = rawReadBuffer.size();
1809 if (!tryDecodeWithGlobalDecoder()) {
1811 bool hasError =
true;
1812 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1813 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1814 hasError = chunkDecoder.hasError();
1817 raiseWellFormedError(
1818 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1823 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1824 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1825 readBuffer = chunkDecoder(bufAndEnc.buffer);
1829 readBuffer.reserve(1);
1831 if (readBufferPos < readBuffer.size()) {
1832 ushort c = readBuffer.at(readBufferPos++).unicode();
1840XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1842 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1843 if (namespaceDeclaration.prefix == prefix) {
1844 return namespaceDeclaration.namespaceUri;
1849 if (namespaceProcessing && !prefix.isEmpty())
1850 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1853 return XmlStringRef();
1859 QStringView namespaceUri;
1861 static AttributeName fromXmlAttribute(
const QXmlStreamAttribute &a,
bool nsProcessing)
1864 return {a.name(), a.namespaceUri()};
1866 return {a.qualifiedName(), a.namespaceUri()};
1869 friend bool operator==(
const AttributeName &lhs,
const AttributeName &rhs)
noexcept
1871 return lhs.name == rhs.name
1872 && lhs.namespaceUri == rhs.namespaceUri;
1874 friend size_t qHash(
const AttributeName &key, size_t seed = 0)
noexcept
1876 return qHashMulti(seed,
1883
1884
1885void QXmlStreamReaderPrivate::resolveTag()
1887 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1888 const qsizetype n = attributeStack.size();
1890 if (namespaceProcessing) {
1891 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1892 if (!dtdAttribute.isNamespaceAttribute
1893 || dtdAttribute.defaultValue.isNull()
1894 || dtdAttribute.tagName != qualifiedName
1895 || dtdAttribute.attributeQualifiedName.isNull())
1898 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1902 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1903 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1904 namespaceDeclaration.prefix.clear();
1906 const XmlStringRef ns(dtdAttribute.defaultValue);
1907 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1908 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1909 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1911 namespaceDeclaration.namespaceUri = ns;
1912 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1913 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1914 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1915 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1916 if (((namespacePrefix ==
"xml"_L1)
1917 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1918 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1919 || namespaceUri.isEmpty()
1920 || namespacePrefix ==
"xmlns"_L1)
1921 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1923 namespaceDeclaration.prefix = namespacePrefix;
1924 namespaceDeclaration.namespaceUri = namespaceUri;
1929 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1931 attributes.resize(n);
1933 Q_DECL_UNINITIALIZED
1934 QDuplicateTracker<AttributeName, 13> names(n);
1936 for (qsizetype i = 0; i < n; ++i) {
1937 QXmlStreamAttribute &attribute = attributes[i];
1938 Attribute &attrib = attributeStack[i];
1939 XmlStringRef prefix(symPrefix(attrib.key));
1940 XmlStringRef name(symString(attrib.key));
1941 XmlStringRef qualifiedName(symName(attrib.key));
1942 XmlStringRef value(symString(attrib.value));
1944 attribute.m_name = name;
1945 attribute.m_qualifiedName = qualifiedName;
1946 attribute.m_value = value;
1948 if (!prefix.isEmpty()) {
1949 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1950 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1953 if (names.hasSeen(AttributeName::fromXmlAttribute(attribute, namespaceProcessing))) {
1954 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1959 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1960 if (dtdAttribute.isNamespaceAttribute
1961 || dtdAttribute.defaultValue.isNull()
1962 || dtdAttribute.tagName != qualifiedName
1963 || dtdAttribute.attributeQualifiedName.isNull())
1966 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1973 QXmlStreamAttribute attribute;
1974 attribute.m_name = dtdAttribute.attributeName;
1975 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1976 attribute.m_value = dtdAttribute.defaultValue;
1978 if (!dtdAttribute.attributePrefix.isEmpty()) {
1979 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1980 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1989 if (namespaceProcessing && names.hasSeen(AttributeName::fromXmlAttribute(attribute,
true))) {
1990 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1994 attribute.m_isDefault =
true;
1995 attributes.append(std::move(attribute));
1999void QXmlStreamReaderPrivate::resolvePublicNamespaces()
2001 const Tag &tag = tagStack.top();
2002 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
2003 publicNamespaceDeclarations.resize(n);
2004 for (qsizetype i = 0; i < n; ++i) {
2005 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
2006 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
2007 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
2008 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
2012void QXmlStreamReaderPrivate::resolveDtd()
2014 publicNotationDeclarations.resize(notationDeclarations.size());
2015 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
2016 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
2017 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
2018 publicNotationDeclaration.m_name = notationDeclaration.name;
2019 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
2020 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
2023 notationDeclarations.clear();
2024 publicEntityDeclarations.resize(entityDeclarations.size());
2025 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
2026 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
2027 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
2028 publicEntityDeclaration.m_name = entityDeclaration.name;
2029 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
2030 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
2031 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
2032 publicEntityDeclaration.m_value = entityDeclaration.value;
2034 entityDeclarations.clear();
2035 parameterEntityHash.clear();
2038uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
2043 if (sym(symbolIndex).c ==
'x')
2044 s = symString(symbolIndex).view().sliced(1).toUInt(&ok, 16);
2046 s = symString(symbolIndex).view().toUInt(&ok, 10);
2048 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
2049 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
2055void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
2059 const char16_t *data = publicId.utf16();
2062 for (i = publicId.size() - 1; i >= 0; --i) {
2064 switch ((c = data[i])) {
2065 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
2066 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
2067 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
2068 case '$':
case '_':
case '%':
case '\'':
case '\"':
2071 if (isAsciiLetterOrNumber(c))
2077 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
2081
2082
2083
2084
2085bool QXmlStreamReaderPrivate::checkStartDocument()
2087 hasCheckedStartDocument =
true;
2089 if (scanString(spell[XML], XML))
2092 type = QXmlStreamReader::StartDocument;
2094 hasCheckedStartDocument =
false;
2095 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2100void QXmlStreamReaderPrivate::startDocument()
2103 if (documentVersion !=
"1.0"_L1) {
2104 if (documentVersion.view().contains(u' '))
2105 err = QXmlStream::tr(
"Invalid XML version string.");
2107 err = QXmlStream::tr(
"Unsupported XML version.");
2109 qsizetype n = attributeStack.size();
2112
2113
2114
2116 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2117 Attribute &attrib = attributeStack[i];
2118 XmlStringRef prefix(symPrefix(attrib.key));
2119 XmlStringRef key(symString(attrib.key));
2120 XmlStringRef value(symString(attrib.value));
2122 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2123 documentEncoding = value;
2126 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2127 if (!QXmlUtils::isEncName(value))
2128 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2130 QByteArray enc = value.toString().toUtf8();
2131 if (!lockEncoding) {
2132 decoder = QStringDecoder(enc.constData());
2133 if (!decoder.isValid()) {
2137 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2138 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2140 decoder = QStringDecoder(QStringDecoder::Utf8);
2141 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2147 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2148 if (!decoder.hasError())
2149 readBuffer = std::move(buf);
2153 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2154 hasStandalone =
true;
2155 if (value ==
"yes"_L1)
2157 else if (value ==
"no"_L1)
2160 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2162 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2167 raiseWellFormedError(err);
2168 attributeStack.clear();
2172void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2174 this->error = error;
2175 errorString = message;
2176 if (errorString.isNull()) {
2177 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2178 errorString = QXmlStream::tr(
"Premature end of document.");
2179 else if (error == QXmlStreamReader::CustomError)
2180 errorString = QXmlStream::tr(
"Invalid document.");
2183 type = QXmlStreamReader::Invalid;
2186void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2188 raiseError(QXmlStreamReader::NotWellFormedError, message);
2191void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2194 raiseError(QXmlStreamReader::NotWellFormedError,
2195 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2199void QXmlStreamReaderPrivate::parseError()
2202 if (token == EOF_SYMBOL) {
2203 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2207 QString error_message;
2208 int ers = state_stack[tos];
2211 if (token != XML_ERROR)
2212 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2213 int k = t_action(ers, tk);
2217 if (nexpected < nmax)
2218 expected[nexpected++] = tk;
2222 if (nexpected && nexpected < nmax) {
2224 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2225 .arg(QLatin1StringView(spell[expected[0]]));
2226 if (nexpected == 2) {
2228 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2229 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2230 }
else if (nexpected > 2) {
2232 for (; s < nexpected - 1; ++s) {
2234 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2235 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2238 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2239 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2241 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2242 .arg(exp_str, QLatin1StringView(spell[token]));
2244 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2247 raiseWellFormedError(error_message);
2250void QXmlStreamReaderPrivate::resume(
int rule) {
2251 resumeReduction = rule;
2252 if (error == QXmlStreamReader::NoError)
2253 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2257
2258
2259
2260qint64 QXmlStreamReader::lineNumber()
const
2262 Q_D(
const QXmlStreamReader);
2263 return d->lineNumber + 1;
2267
2268
2269
2270qint64 QXmlStreamReader::columnNumber()
const
2272 Q_D(
const QXmlStreamReader);
2273 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2277
2278
2279
2280qint64 QXmlStreamReader::characterOffset()
const
2282 Q_D(
const QXmlStreamReader);
2283 return d->characterOffset + d->readBufferPos;
2288
2289
2290QStringView QXmlStreamReader::text()
const
2292 Q_D(
const QXmlStreamReader);
2298
2299
2300
2301
2302
2303QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2305 Q_D(
const QXmlStreamReader);
2306 if (!d->scanDtd && !d->notationDeclarations.isEmpty())
2307 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2308 return d->publicNotationDeclarations;
2313
2314
2315
2316
2317
2318QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2320 Q_D(
const QXmlStreamReader);
2321 if (!d->scanDtd && !d->entityDeclarations.isEmpty())
2322 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2323 return d->publicEntityDeclarations;
2327
2328
2329
2330
2331
2332
2333QStringView QXmlStreamReader::dtdName()
const
2335 Q_D(
const QXmlStreamReader);
2336 if (d->type == QXmlStreamReader::DTD)
2338 return QStringView();
2342
2343
2344
2345
2346
2347
2348QStringView QXmlStreamReader::dtdPublicId()
const
2350 Q_D(
const QXmlStreamReader);
2351 if (d->type == QXmlStreamReader::DTD)
2352 return d->dtdPublicId;
2353 return QStringView();
2357
2358
2359
2360
2361
2362
2363QStringView QXmlStreamReader::dtdSystemId()
const
2365 Q_D(
const QXmlStreamReader);
2366 if (d->type == QXmlStreamReader::DTD)
2367 return d->dtdSystemId;
2368 return QStringView();
2372
2373
2374
2375
2376
2377
2378
2379
2380int QXmlStreamReader::entityExpansionLimit()
const
2382 Q_D(
const QXmlStreamReader);
2383 return d->entityExpansionLimit;
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2405 Q_D(QXmlStreamReader);
2407 qWarning(
"QXmlStreamReader::setEntityExpansionLimit(): "
2408 "limit %d is out of range [1:INT_MAX], clamping to 1.", limit);
2410 d->entityExpansionLimit = (std::max)(limit, 1);
2414
2415
2416
2417
2418
2419
2420
2421
2422QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2424 Q_D(
const QXmlStreamReader);
2425 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2426 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2427 return d->publicNamespaceDeclarations;
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2443 Q_D(QXmlStreamReader);
2444 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2445 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2446 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2450
2451
2452
2453
2454
2455
2456void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2458 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2459 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2482 Q_D(QXmlStreamReader);
2483 if (isStartElement()) {
2485 qsizetype nestingLevel = 1;
2487 switch (readNext()) {
2489 case EntityReference:
2490 result.insert(result.size(), d->text);
2495 case ProcessingInstruction:
2499 if (behaviour == SkipChildElements) {
2500 skipCurrentElement();
2502 }
else if (behaviour == IncludeChildElements) {
2508 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2510 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2514 }
while (nestingLevel);
2521
2522
2523
2524void QXmlStreamReader::raiseError(
const QString& message)
2526 Q_D(QXmlStreamReader);
2527 d->raiseError(CustomError, message);
2531
2532
2533
2534
2535QString QXmlStreamReader::errorString()
const
2537 Q_D(
const QXmlStreamReader);
2538 if (d->type == QXmlStreamReader::Invalid)
2539 return d->errorString;
2544
2545
2546
2547QXmlStreamReader::Error QXmlStreamReader::error()
const
2549 Q_D(
const QXmlStreamReader);
2550 if (d->type == QXmlStreamReader::Invalid)
2556
2557
2558QStringView QXmlStreamReader::processingInstructionTarget()
const
2560 Q_D(
const QXmlStreamReader);
2561 return d->processingInstructionTarget;
2565
2566
2567QStringView QXmlStreamReader::processingInstructionData()
const
2569 Q_D(
const QXmlStreamReader);
2570 return d->processingInstructionData;
2576
2577
2578
2579
2580QStringView QXmlStreamReader::name()
const
2582 Q_D(
const QXmlStreamReader);
2587
2588
2589
2590
2591QStringView QXmlStreamReader::namespaceUri()
const
2593 Q_D(
const QXmlStreamReader);
2594 return d->namespaceUri;
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609QStringView QXmlStreamReader::qualifiedName()
const
2611 Q_D(
const QXmlStreamReader);
2612 return d->qualifiedName;
2618
2619
2620
2621
2622
2623
2624QStringView QXmlStreamReader::prefix()
const
2626 Q_D(
const QXmlStreamReader);
2631
2632
2633QXmlStreamAttributes QXmlStreamReader::attributes()
const
2635 Q_D(
const QXmlStreamReader);
2636 return d->attributes;
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2659
2660
2661QXmlStreamAttribute::QXmlStreamAttribute()
2663 m_isDefault =
false;
2667
2668
2669
2670
2671QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2672 : m_isDefault(
false)
2674 m_namespaceUri = namespaceUri;
2675 m_name = m_qualifiedName = name;
2680
2681
2682
2683
2684QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2685 : m_isDefault(
false)
2687 qsizetype colon = qualifiedName.indexOf(u':');
2688 m_name = qualifiedName.mid(colon + 1);
2689 m_qualifiedName = qualifiedName;
2694
2695
2696
2697
2699
2700
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2713
2714
2715
2716
2717
2718
2719
2722
2723
2726
2727
2728
2729
2730
2732
2733
2734
2735
2737
2738
2739
2740
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2765
2766
2767
2768
2771
2772
2773
2774
2775
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2793
2794
2795QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2800
2801
2802
2804
2805
2806
2808
2809
2810
2813
2814
2815
2816
2818
2819
2820
2821
2824
2825
2826
2827
2828
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2844
2845
2846
2847
2849
2850
2851
2852
2855
2856
2857QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2862
2863
2864
2865
2866QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2869 m_namespaceUri = namespaceUri;
2873
2874
2875
2877
2878
2879
2885
2886
2887
2888
2889
2892
2893
2894
2895
2896
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2913
2914
2915QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2920
2921
2922
2924
2925
2926
2928
2929
2930
2932
2933
2934
2936
2937
2938
2941
2942
2943
2944
2946
2947
2948
2949
2952
2953
2954
2955
2956
2957
2958QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2960 for (
const QXmlStreamAttribute &attribute : *
this) {
2961 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2962 return attribute.value();
2964 return QStringView();
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2985 for (
const QXmlStreamAttribute &attribute : *
this) {
2986 if (attribute.qualifiedName() == qualifiedName)
2987 return attribute.value();
2989 return QStringView();
2993
2994
2995
2996void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2998 append(QXmlStreamAttribute(namespaceUri, name, value));
3002
3003
3004
3005void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
3007 append(QXmlStreamAttribute(qualifiedName, value));
3010#if QT_CONFIG(xmlstreamreader)
3013
3014
3016
3017
3019
3020
3022
3023
3025
3026
3027
3028
3030
3031
3033
3034
3036
3037
3039
3040
3043
3044
3045
3046
3047bool QXmlStreamReader::isWhitespace()
const
3049 Q_D(
const QXmlStreamReader);
3050 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
3054
3055
3056
3057
3058bool QXmlStreamReader::isCDATA()
const
3060 Q_D(
const QXmlStreamReader);
3061 return d->type == QXmlStreamReader::Characters && d->isCDATA;
3067
3068
3069
3070
3071
3072
3073
3074bool QXmlStreamReader::isStandaloneDocument()
const
3076 Q_D(
const QXmlStreamReader);
3077 return d->standalone;
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090bool QXmlStreamReader::hasStandaloneDeclaration()
const
3092 Q_D(
const QXmlStreamReader);
3093 return d->hasStandalone;
3097
3098
3099
3100
3101
3102
3103QStringView QXmlStreamReader::documentVersion()
const
3105 Q_D(
const QXmlStreamReader);
3106 if (d->type == QXmlStreamReader::StartDocument)
3107 return d->documentVersion;
3108 return QStringView();
3112
3113
3114
3115
3116
3117
3118QStringView QXmlStreamReader::documentEncoding()
const
3120 Q_D(
const QXmlStreamReader);
3121 if (d->type == QXmlStreamReader::StartDocument)
3122 return d->documentEncoding;
3123 return QStringView();
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
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3244#if QT_CONFIG(xmlstreamwriter)
3246class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3248 QXmlStreamWriter *q_ptr;
3249 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3251 enum class StartElementOption {
3253 OmitNamespaceDeclarations = 1,
3256 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3257 ~QXmlStreamWriterPrivate() {
3262 void raiseError(QXmlStreamWriter::Error error);
3263 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3264 void write(QAnyStringView s);
3265 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3266 bool finishStartElement(
bool contents =
true);
3267 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3268 StartElementOption option = StartElementOption::KeepEverything);
3269 QIODevice *device =
nullptr;
3270 QString *stringDevice =
nullptr;
3271 uint deleteDevice :1;
3272 uint inStartElement :1;
3273 uint inEmptyElement :1;
3274 uint lastWasStartElement :1;
3275 uint wroteSomething :1;
3276 uint autoFormatting :1;
3277 uint didWriteStartDocument :1;
3278 uint didWriteAnyToken :1;
3279 uint stopWritingOnError :1;
3280 std::string autoFormattingIndent = std::string(4,
' ');
3281 NamespaceDeclaration emptyNamespace;
3282 qsizetype lastNamespaceDeclaration = 1;
3283 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3284 QString errorString;
3286 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3287 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3288 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3290 int namespacePrefixCount = 0;
3292 void indent(
int level);
3294 void doWriteToDevice(QStringView s);
3295 void doWriteToDevice(QUtf8StringView s);
3296 void doWriteToDevice(QLatin1StringView s);
3300QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3301 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3302 inEmptyElement(
false), lastWasStartElement(
false),
3303 wroteSomething(
false), autoFormatting(
false),
3304 didWriteStartDocument(
false), didWriteAnyToken(
false),
3305 stopWritingOnError(
false)
3309void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3313 case QXmlStreamWriter::Error::IO:
3314 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3316 case QXmlStreamWriter::Error::Encoding:
3317 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3319 case QXmlStreamWriter::Error::InvalidCharacter:
3320 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3322 case QXmlStreamWriter::Error::Custom:
3323 errorString = QXmlStream::tr(
"An error occurred while writing");
3325 case QXmlStreamWriter::Error::None:
3326 errorString.clear();
3331void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3334 errorString = message.toString();
3337void QXmlStreamWriterPrivate::write(QAnyStringView s)
3339 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3342 if (error == QXmlStreamWriter::Error::IO)
3345 s.visit([&] (
auto s) { doWriteToDevice(s); });
3346 }
else if (stringDevice) {
3347 s.visit([&] (
auto s) { stringDevice->append(s); });
3349 qWarning(
"QXmlStreamWriter: No device");
3353void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3360 NextResult operator()(
const char *&it,
const char *)
const
3361 {
return {uchar(*it++),
false}; }
3364 NextResult operator()(
const char *&it,
const char *end)
const
3368 constexpr char32_t invalidValue = 0xFFFFFFFF;
3369 static_assert(invalidValue > QChar::LastValidCodePoint);
3370 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3371 const auto old_i = i;
3372 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3373 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3375 return result == invalidValue ? NextResult{U'\0',
true}
3376 : NextResult{result,
false};
3380 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3382 QStringIterator decoder(it, end);
3385 constexpr char32_t invalidValue = 0xFFFFFFFF;
3386 static_assert(invalidValue > QChar::LastValidCodePoint);
3387 char32_t result = decoder.next(invalidValue);
3388 it = decoder.position();
3389 return result == invalidValue ? NextResult{U'\0',
true}
3390 : NextResult{result,
false};
3395 escaped.reserve(s.size());
3396 s.visit([&] (
auto s) {
3397 using View =
decltype(s);
3398 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3399 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3401 auto it = s.begin();
3402 const auto end = s.end();
3406 QLatin1StringView replacement;
3411 const auto decoded = decoder(next_it, end);
3412 switch (decoded.value) {
3414 replacement =
"<"_L1;
3417 replacement =
">"_L1;
3420 replacement =
"&"_L1;
3423 replacement =
"""_L1;
3426 if (escapeWhitespace)
3427 replacement =
"	"_L1;
3430 if (escapeWhitespace)
3431 replacement =
" "_L1;
3434 if (escapeWhitespace)
3435 replacement =
" "_L1;
3439 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3440 if (stopWritingOnError)
3442 replacement =
""_L1;
3443 Q_ASSERT(!replacement.isNull());
3446 if (decoded.value > 0x1F)
3452 raiseError(decoded.encodingError
3453 ? QXmlStreamWriter::Error::Encoding
3454 : QXmlStreamWriter::Error::InvalidCharacter);
3455 if (stopWritingOnError)
3457 replacement =
""_L1;
3458 Q_ASSERT(!replacement.isNull());
3461 if (!replacement.isNull())
3466 escaped.append(View{mark, it});
3467 escaped.append(replacement);
3476void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3477 if (namespaceDeclaration.prefix.isEmpty()) {
3479 write(namespaceDeclaration.namespaceUri);
3483 write(namespaceDeclaration.prefix);
3485 write(namespaceDeclaration.namespaceUri);
3488 didWriteAnyToken =
true;
3491bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3493 bool hadSomethingWritten = wroteSomething;
3494 wroteSomething = contents;
3495 if (!inStartElement)
3496 return hadSomethingWritten;
3498 if (inEmptyElement) {
3500 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3501 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3502 lastWasStartElement =
false;
3506 inStartElement = inEmptyElement =
false;
3507 lastNamespaceDeclaration = namespaceDeclarations.size();
3508 didWriteAnyToken =
true;
3509 return hadSomethingWritten;
3512QXmlStreamPrivateTagStack::NamespaceDeclaration &
3513QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3515 const bool prefixIsXml = prefix ==
"xml"_L1;
3516 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3517 if (prefixIsXml && !namespaceUriIsXml) {
3518 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3519 "than 'http://www.w3.org/XML/1998/namespace'");
3520 }
else if (!prefixIsXml && namespaceUriIsXml) {
3521 const QString prefixString = prefix.toString();
3522 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3523 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3524 qUtf16Printable(prefixString));
3526 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3527 const QString prefixString = prefix.toString();
3528 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3529 "'http://www.w3.org/2000/xmlns/'",
3530 qUtf16Printable(prefixString));
3532 auto &namespaceDeclaration = namespaceDeclarations.push();
3533 namespaceDeclaration.prefix = addToStringStorage(prefix);
3534 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3535 return namespaceDeclaration;
3538QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3540 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3541 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3542 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3543 return namespaceDeclaration;
3546 if (namespaceUri.isEmpty())
3547 return emptyNamespace;
3548 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3549 if (namespaceUri.isEmpty()) {
3550 namespaceDeclaration.prefix.clear();
3553 int n = ++namespacePrefixCount;
3555 s = u'n' + QString::number(n++);
3556 qsizetype j = namespaceDeclarations.size() - 2;
3557 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3562 namespaceDeclaration.prefix = addToStringStorage(s);
3564 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3565 if (writeDeclaration)
3566 writeNamespaceDeclaration(namespaceDeclaration);
3567 return namespaceDeclaration;
3572void QXmlStreamWriterPrivate::indent(
int level)
3574 if (didWriteStartDocument || didWriteAnyToken)
3576 for (
int i = 0; i < level; ++i)
3577 write(autoFormattingIndent);
3580void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3582 constexpr qsizetype MaxChunkSize = 512;
3583 char buffer [3 * MaxChunkSize];
3584 QStringEncoder::State state;
3585 while (!s.isEmpty()) {
3586 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3587 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3588 doWriteToDevice(QUtf8StringView{buffer, end});
3589 s = s.sliced(chunkSize);
3591 if (state.remainingChars > 0)
3592 raiseError(QXmlStreamWriter::Error::Encoding);
3595void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3597 QByteArrayView bytes = s;
3598 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3599 raiseError(QXmlStreamWriter::Error::IO);
3602void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3604 constexpr qsizetype MaxChunkSize = 512;
3605 char buffer [2 * MaxChunkSize];
3606 while (!s.isEmpty()) {
3607 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3608 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3609 doWriteToDevice(QUtf8StringView{buffer, end});
3610 s = s.sliced(chunkSize);
3615
3616
3617
3618
3619QXmlStreamWriter::QXmlStreamWriter()
3620 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3625
3626
3627QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3628 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3630 Q_D(QXmlStreamWriter);
3635
3636
3637
3638QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3639 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3641 Q_D(QXmlStreamWriter);
3642 d->device =
new QBuffer(array);
3643 d->device->open(QIODevice::WriteOnly);
3644 d->deleteDevice =
true;
3649
3650QXmlStreamWriter::QXmlStreamWriter(QString *string)
3651 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3653 Q_D(QXmlStreamWriter);
3654 d->stringDevice = string;
3658
3659
3660QXmlStreamWriter::~QXmlStreamWriter()
3666
3667
3668
3669
3670
3671void QXmlStreamWriter::setDevice(QIODevice *device)
3673 Q_D(QXmlStreamWriter);
3674 if (device == d->device)
3676 d->stringDevice =
nullptr;
3677 if (d->deleteDevice) {
3679 d->deleteDevice =
false;
3685
3686
3687
3688
3689
3690QIODevice *QXmlStreamWriter::device()
const
3692 Q_D(
const QXmlStreamWriter);
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3713
3714
3715
3716
3717
3718
3719
3720void QXmlStreamWriter::setAutoFormatting(
bool enable)
3722 Q_D(QXmlStreamWriter);
3723 d->autoFormatting = enable;
3727
3728
3729
3730
3731bool QXmlStreamWriter::autoFormatting()
const
3733 Q_D(
const QXmlStreamWriter);
3734 return d->autoFormatting;
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3751void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3753 Q_D(QXmlStreamWriter);
3754 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3757int QXmlStreamWriter::autoFormattingIndent()
const
3759 Q_D(
const QXmlStreamWriter);
3760 const QLatin1StringView indent(d->autoFormattingIndent);
3761 return indent.count(u' ') - indent.count(u'\t');
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781bool QXmlStreamWriter::stopWritingOnError()
const
3783 Q_D(
const QXmlStreamWriter);
3784 return d->stopWritingOnError;
3787void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3789 Q_D(QXmlStreamWriter);
3790 d->stopWritingOnError = stop;
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805bool QXmlStreamWriter::hasError()
const
3807 return error() != QXmlStreamWriter::Error::None;
3811
3812
3813
3814
3815
3816
3817
3818
3819QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3821 Q_D(
const QXmlStreamWriter);
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835QString QXmlStreamWriter::errorString()
const
3837 Q_D(
const QXmlStreamWriter);
3838 return d->errorString;
3842
3843
3844
3845
3846
3847
3848
3849
3850void QXmlStreamWriter::raiseError(QAnyStringView message)
3852 Q_D(QXmlStreamWriter);
3853 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3869 Q_D(QXmlStreamWriter);
3870 Q_ASSERT(d->inStartElement);
3871 Q_ASSERT(count(qualifiedName,
':') <= 1);
3873 d->write(qualifiedName);
3875 d->writeEscaped(value,
true);
3877 d->didWriteAnyToken =
true;
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3893 Q_D(QXmlStreamWriter);
3894 Q_ASSERT(d->inStartElement);
3895 Q_ASSERT(!contains(name,
':'));
3896 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3898 if (!namespaceDeclaration.prefix.isEmpty()) {
3899 d->write(namespaceDeclaration.prefix);
3904 d->writeEscaped(value,
true);
3906 d->didWriteAnyToken =
true;
3910
3911
3912
3913
3914
3915
3916
3917void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3919 if (attribute.namespaceUri().isEmpty())
3920 writeAttribute(attribute.qualifiedName(), attribute.value());
3922 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3927
3928
3929
3930
3931
3932
3933
3934
3935void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3937 Q_D(QXmlStreamWriter);
3938 Q_ASSERT(d->inStartElement);
3940 for (
const auto &attr : attributes)
3941 writeAttribute(attr);
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3958 Q_D(QXmlStreamWriter);
3959 d->finishStartElement();
3960 d->write(
"<![CDATA[");
3961 while (!text.isEmpty()) {
3962 const auto idx = indexOf(text,
"]]>"_L1);
3965 d->write(text.first(idx));
3969 text = text.sliced(idx + 3);
3977
3978
3979
3980
3981
3982
3983
3984
3985void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3987 Q_D(QXmlStreamWriter);
3988 d->finishStartElement();
3989 d->writeEscaped(text);
3994
3995
3996
3997
3998
3999
4000void QXmlStreamWriter::writeComment(QAnyStringView text)
4002 Q_D(QXmlStreamWriter);
4003 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
4004 if (!d->finishStartElement(
false) && d->autoFormatting)
4005 d->indent(d->tagStack.size());
4009 d->inStartElement = d->lastWasStartElement =
false;
4014
4015
4016
4017
4018
4019void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
4021 Q_D(QXmlStreamWriter);
4022 d->finishStartElement();
4023 if (d->autoFormatting)
4026 if (d->autoFormatting)
4033
4034
4035
4036
4037
4038
4039void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
4041 Q_D(QXmlStreamWriter);
4042 Q_ASSERT(count(qualifiedName,
':') <= 1);
4043 d->writeStartElement({}, qualifiedName);
4044 d->inEmptyElement =
true;
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
4060 Q_D(QXmlStreamWriter);
4061 Q_ASSERT(!contains(name,
':'));
4062 d->writeStartElement(namespaceUri, name);
4063 d->inEmptyElement =
true;
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
4079 writeStartElement(qualifiedName);
4080 writeCharacters(text);
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
4098 writeStartElement(namespaceUri, name);
4099 writeCharacters(text);
4105
4106
4107
4108
4109void QXmlStreamWriter::writeEndDocument()
4111 Q_D(QXmlStreamWriter);
4112 while (d->tagStack.size())
4114 if (d->didWriteStartDocument || d->didWriteAnyToken)
4119
4120
4121
4122
4123void QXmlStreamWriter::writeEndElement()
4125 Q_D(QXmlStreamWriter);
4126 Q_ASSERT(d->didWriteAnyToken);
4127 if (d->tagStack.isEmpty())
4131 if (d->inStartElement && !d->inEmptyElement) {
4133 d->lastWasStartElement = d->inStartElement =
false;
4134 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4135 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4139 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4140 d->indent(d->tagStack.size()-1);
4141 if (d->tagStack.isEmpty())
4143 d->lastWasStartElement =
false;
4144 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4145 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4147 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4148 d->write(tag.namespaceDeclaration.prefix);
4158
4159
4160
4161
4162
4163void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4165 Q_D(QXmlStreamWriter);
4166 d->finishStartElement();
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4192 Q_D(QXmlStreamWriter);
4193 Q_ASSERT(prefix !=
"xmlns"_L1);
4194 if (prefix.isEmpty()) {
4195 d->findNamespace(namespaceUri, d->inStartElement);
4197 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4198 if (d->inStartElement)
4199 d->writeNamespaceDeclaration(namespaceDeclaration);
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4219 Q_D(QXmlStreamWriter);
4220 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4221 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4222 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4223 namespaceDeclaration.prefix.clear();
4224 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4225 if (d->inStartElement)
4226 d->writeNamespaceDeclaration(namespaceDeclaration);
4231
4232
4233
4234
4235
4236
4237void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4239 Q_D(QXmlStreamWriter);
4240 Q_ASSERT(!contains(data,
"?>"_L1));
4241 if (!d->finishStartElement(
false) && d->autoFormatting)
4242 d->indent(d->tagStack.size());
4245 if (!data.isNull()) {
4250 d->didWriteAnyToken =
true;
4256
4257
4258
4259
4260
4261
4262void QXmlStreamWriter::writeStartDocument()
4264 writeStartDocument(
"1.0"_L1);
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4286 Q_D(QXmlStreamWriter);
4287 d->finishStartElement(
false);
4288 d->write(
"<?xml version=\"");
4291 d->write(
"\" encoding=\"UTF-8");
4293 d->didWriteStartDocument =
true;
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4316 Q_D(QXmlStreamWriter);
4317 d->finishStartElement(
false);
4318 d->write(
"<?xml version=\"");
4321 d->write(
"\" encoding=\"UTF-8");
4323 d->write(
"\" standalone=\"yes\"?>");
4325 d->write(
"\" standalone=\"no\"?>");
4326 d->didWriteStartDocument =
true;
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4342 Q_D(QXmlStreamWriter);
4343 Q_ASSERT(count(qualifiedName,
':') <= 1);
4344 d->writeStartElement({}, qualifiedName);
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4361 Q_D(QXmlStreamWriter);
4362 Q_ASSERT(!contains(name,
':'));
4363 d->writeStartElement(namespaceUri, name);
4366void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4367 StartElementOption option)
4369 if (!finishStartElement(
false) && autoFormatting)
4370 indent(tagStack.size());
4372 Tag &tag = tagStack_push();
4373 tag.name = addToStringStorage(name);
4374 tag.namespaceDeclaration = findNamespace(namespaceUri);
4376 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4377 write(tag.namespaceDeclaration.prefix);
4381 inStartElement = lastWasStartElement =
true;
4383 if (option != StartElementOption::OmitNamespaceDeclarations) {
4384 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4385 writeNamespaceDeclaration(namespaceDeclarations[i]);
4387 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4388 didWriteAnyToken =
true;
4391#if QT_CONFIG(xmlstreamreader)
4393
4394
4395
4396
4397
4398
4399void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4401 Q_D(QXmlStreamWriter);
4402 switch (reader.tokenType()) {
4403 case QXmlStreamReader::NoToken:
4405 case QXmlStreamReader::StartDocument:
4406 writeStartDocument();
4408 case QXmlStreamReader::EndDocument:
4411 case QXmlStreamReader::StartElement: {
4413 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4414 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4415 for (
const auto &namespaceDeclaration : nsDeclarations) {
4416 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4417 namespaceDeclaration.prefix());
4418 extraNamespaces.append(extraNamespace);
4420 d->writeStartElement(
4421 reader.namespaceUri(), reader.name(),
4422 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4424 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4425 d->writeNamespaceDeclaration(extraNamespace);
4426 writeAttributes(reader.attributes());
4428 case QXmlStreamReader::EndElement:
4431 case QXmlStreamReader::Characters:
4432 if (reader.isCDATA())
4433 writeCDATA(reader.text());
4435 writeCharacters(reader.text());
4437 case QXmlStreamReader::Comment:
4438 writeComment(reader.text());
4440 case QXmlStreamReader::DTD:
4441 writeDTD(reader.text());
4443 case QXmlStreamReader::EntityReference:
4444 writeEntityReference(reader.name());
4446 case QXmlStreamReader::ProcessingInstruction:
4447 writeProcessingInstruction(reader.processingInstructionTarget(),
4448 reader.processingInstructionData());
4451 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4452 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4459#if QT_CONFIG(xmlstreamreader)
4460static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4461 QXmlStreamReaderPrivate::XmlContext ctxt)
4464 case QXmlStreamReader::StartDocument:
4465 case QXmlStreamReader::DTD:
4466 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4468 case QXmlStreamReader::StartElement:
4469 case QXmlStreamReader::EndElement:
4470 case QXmlStreamReader::Characters:
4471 case QXmlStreamReader::EntityReference:
4472 case QXmlStreamReader::EndDocument:
4473 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4475 case QXmlStreamReader::Comment:
4476 case QXmlStreamReader::ProcessingInstruction:
4479 case QXmlStreamReader::NoToken:
4480 case QXmlStreamReader::Invalid:
4485#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4486 Q_UNREACHABLE_RETURN(
false);
4493
4494
4495
4496
4497
4498
4499bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4502 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4506 const bool result = isTokenAllowedInContext(type, currentContext);
4507 if (result || currentContext == XmlContext::Body)
4511 currentContext = XmlContext::Body;
4512 return isTokenAllowedInContext(type, currentContext);
4516
4517
4518
4519
4520void QXmlStreamReaderPrivate::checkToken()
4522 Q_Q(QXmlStreamReader);
4525 const XmlContext context = currentContext;
4526 const bool ok = isValidToken(type);
4529 if (error != QXmlStreamReader::Error::NoError)
4533 raiseError(QXmlStreamReader::UnexpectedElementError,
4534 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4535 .arg(q->tokenString(), contextString(context)));
4539 if (type != QXmlStreamReader::DTD)
4544 raiseError(QXmlStreamReader::UnexpectedElementError,
4545 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4566
4567
4568
4569
4570
4571
4572
4573