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();
1067 dtdAttributes.clear();
1069 lastAttributeIsCData =
false;
1072 isEmptyElement =
false;
1073 isWhitespace =
true;
1076 hasStandalone =
false;
1078 resumeReduction = 0;
1079 state_stack[tos++] = 0;
1080 state_stack[tos] = 0;
1082 putStack.reserve(32);
1084 dtdPublicId.clear();
1085 dtdSystemId.clear();
1086 entityDeclarations.clear();
1087 entityDeclarations.reserve(16);
1088 publicEntityDeclarations.clear();
1089 notationDeclarations.clear();
1090 notationDeclarations.reserve(16);
1091 publicNotationDeclarations.clear();
1093 textBuffer.reserve(256);
1097 attributes.reserve(16);
1098 lineNumber = lastLineStart = characterOffset = 0;
1101 decoder = QStringDecoder();
1102 attributeStack.clear();
1103 attributeStack.reserve(16);
1104 entityReferenceStack.clear();
1105 entityReferenceStack.reserve(16);
1107 entityParser.reset();
1108 hasCheckedStartDocument =
false;
1109 normalizeLiterals =
false;
1112 inParseEntity =
false;
1113 referenceToUnparsedEntityDetected =
false;
1114 referenceToParameterEntityDetected =
false;
1115 hasExternalDtdSubset =
false;
1116 lockEncoding =
false;
1117 namespaceProcessing =
true;
1118 rawReadBuffer.clear();
1119 chunkDecoder = QStringDecoder();
1122 tagStackStringStorageSize = initialTagStackStringStorageSize;
1124 type = QXmlStreamReader::NoToken;
1125 error = QXmlStreamReader::NoError;
1126 currentContext = XmlContext::Prolog;
1131
1132
1133
1134void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1136 Q_Q(QXmlStreamReader);
1138 if (value.isEmpty())
1143 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1145 entityParser->init();
1146 entityParser->inParseEntity =
true;
1147 entityParser->readBuffer = value;
1148 entityParser->injectToken(PARSE_ENTITY);
1149 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1150 entityParser->parse();
1151 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1152 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1156inline void QXmlStreamReaderPrivate::reallocateStack()
1161 const auto newStackSize = stack_size * 2;
1163 void *p = qt_reallocarray(sym_stack, size_t(newStackSize),
sizeof(Value));
1165 sym_stack =
static_cast<Value*>(p);
1166 p = qt_reallocarray(state_stack, size_t(newStackSize),
sizeof(
int));
1168 state_stack =
static_cast<
int*>(p);
1171 stack_size = newStackSize;
1175QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1182inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1184 uint peekc = peekChar();
1185 if (peekc ==
'\n') {
1186 if (putStack.size())
1192 if (peekc == StreamEOF) {
1200
1201
1202
1203inline uint QXmlStreamReaderPrivate::getChar()
1206 if (putStack.size()) {
1207 c = atEnd ? StreamEOF : putStack.pop();
1209 if (readBufferPos < readBuffer.size())
1210 c = readBuffer.at(readBufferPos++).unicode();
1212 c = getChar_helper();
1218inline uint QXmlStreamReaderPrivate::peekChar()
1221 if (putStack.size()) {
1223 }
else if (readBufferPos < readBuffer.size()) {
1224 c = readBuffer.at(readBufferPos).unicode();
1226 if ((c = getChar_helper()) != StreamEOF)
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1247 const qsizetype pos = textBuffer.size();
1248 const auto oldLineNumber = lineNumber;
1251 while ((c = getChar()) != StreamEOF) {
1255 if ((c = filterCarriageReturn()) == 0)
1260 lastLineStart = characterOffset + readBufferPos;
1263 textBuffer += QChar(c);
1266 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1267 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1268 lineNumber = oldLineNumber;
1271 textBuffer += QChar(c);
1276 if (c == uint(*str)) {
1278 if (tokenToInject >= 0)
1279 injectToken(tokenToInject);
1282 if (scanString(str + 1, tokenToInject,
false))
1287 putString(textBuffer, pos);
1288 textBuffer.resize(pos);
1289 lineNumber = oldLineNumber;
1293bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1298 if (c != ushort(str[n])) {
1302 putChar(ushort(str[n]));
1308 textBuffer += QLatin1StringView(str, n);
1310 const qsizetype s = fastScanSpace();
1312 qsizetype pos = textBuffer.size() - n - s;
1313 putString(textBuffer, pos);
1314 textBuffer.resize(pos);
1318 if (tokenToInject >= 0)
1319 injectToken(tokenToInject);
1323bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1325 switch (peekChar()) {
1327 return scanString(spell[CDATA_START], CDATA_START,
false);
1329 return scanString(spell[DOCTYPE], DOCTYPE);
1331 return scanString(spell[ATTLIST], ATTLIST);
1333 return scanString(spell[NOTATION], NOTATION);
1335 if (scanString(spell[ELEMENT], ELEMENT))
1337 return scanString(spell[ENTITY], ENTITY);
1345bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1347 switch (peekChar()) {
1349 return scanString(spell[SYSTEM], SYSTEM);
1351 return scanString(spell[PUBLIC], PUBLIC);
1358bool QXmlStreamReaderPrivate::scanNData()
1360 if (fastScanSpace()) {
1361 if (scanString(spell[NDATA], NDATA))
1368bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1370 switch (peekChar()) {
1372 return scanString(spell[REQUIRED], REQUIRED,
false);
1374 return scanString(spell[IMPLIED], IMPLIED,
false);
1376 return scanString(spell[FIXED], FIXED,
false);
1383bool QXmlStreamReaderPrivate::scanAttType()
1385 switch (peekChar()) {
1387 return scanString(spell[CDATA], CDATA);
1389 if (scanString(spell[ID], ID))
1391 if (scanString(spell[IDREF], IDREF))
1393 return scanString(spell[IDREFS], IDREFS);
1395 if (scanString(spell[ENTITY], ENTITY))
1397 return scanString(spell[ENTITIES], ENTITIES);
1399 if (scanString(spell[NOTATION], NOTATION))
1401 if (scanString(spell[NMTOKEN], NMTOKEN))
1403 return scanString(spell[NMTOKENS], NMTOKENS);
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1426 while ((c = getChar()) != StreamEOF) {
1427 switch (ushort(c)) {
1432
1436 if (filterCarriageReturn() == 0)
1441 lastLineStart = characterOffset + readBufferPos;
1445 if (normalizeLiterals)
1448 textBuffer += QChar(c);
1455 if (!(c & 0xff0000)) {
1465 textBuffer += QChar(ushort(c));
1472inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1476 while ((c = getChar()) != StreamEOF) {
1479 if ((c = filterCarriageReturn()) == 0)
1484 lastLineStart = characterOffset + readBufferPos;
1488 textBuffer += QChar(c);
1500
1501
1502
1503
1504
1505inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1509 while ((c = getChar()) != StreamEOF) {
1510 switch (ushort(c)) {
1517 isWhitespace =
false;
1518 const qsizetype pos = textBuffer.size();
1519 textBuffer += QChar(ushort(c));
1521 while ((c = getChar()) ==
']') {
1522 textBuffer += QChar(ushort(c));
1525 if (c == StreamEOF) {
1526 putString(textBuffer, pos);
1527 textBuffer.resize(pos);
1528 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1529 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1537 if ((c = filterCarriageReturn()) == 0)
1542 lastLineStart = characterOffset + readBufferPos;
1546 textBuffer += QChar(ushort(c));
1551 if (!(c & 0xff0000)) {
1561 isWhitespace =
false;
1562 textBuffer += QChar(ushort(c));
1570inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1574 while ((c = getChar()) != StreamEOF) {
1578 raiseNamePrefixTooLongError();
1579 return std::nullopt;
1608 if (val && val->prefix == n + 1) {
1616 if (val->prefix == 0) {
1617 val->prefix = qint16(n + 2);
1628 textBuffer += QChar(ushort(c));
1635 qsizetype pos = textBuffer.size() - n;
1636 putString(textBuffer, pos);
1637 textBuffer.resize(pos);
1641enum NameChar { NameBeginning, NameNotBeginning, NotName };
1643static const char Begi =
static_cast<
char>(NameBeginning);
1644static const char NtBg =
static_cast<
char>(NameNotBeginning);
1645static const char NotN =
static_cast<
char>(NotName);
1647static const char nameCharTable[128] =
1650 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1651 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1653 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1654 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1656 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1657 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1659 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1660 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1662 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1663 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1665 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1666 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1668 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1669 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1671 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1672 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1675static inline NameChar fastDetermineNameChar(QChar ch)
1677 ushort uc = ch.unicode();
1679 return static_cast<NameChar>(nameCharTable[uc]);
1681 QChar::Category cat = ch.category();
1683 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1684 || cat == QChar::Number_Letter)
1685 return NameBeginning;
1686 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1687 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1688 return NameNotBeginning;
1692inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1696 while ((c = getChar()) != StreamEOF) {
1697 if (fastDetermineNameChar(QChar(c)) == NotName) {
1702 textBuffer += QChar(c);
1706 qsizetype pos = textBuffer.size() - n;
1707 putString(textBuffer, pos);
1708 textBuffer.resize(pos);
1713void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1716 putString(s.mid(from));
1719 putStack.reserve(s.size());
1720 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1721 putStack.rawPush() = it->unicode();
1724void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1726 putStack.reserve(s.size());
1727 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1728 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1731void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1733 putStack.reserve(s.size());
1734 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1735 char16_t c = it->unicode();
1736 if (c ==
'\n' || c ==
'\r')
1737 putStack.rawPush() = ((LETTER << 16) | c);
1739 putStack.rawPush() = c;
1742void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1744 putStack.reserve(s.size());
1745 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1746 char16_t c = it->unicode();
1747 if (c ==
'&' || c ==
';')
1748 putStack.rawPush() = c;
1749 else if (c ==
'\n' || c ==
'\r')
1750 putStack.rawPush() =
' ';
1752 putStack.rawPush() = ((LETTER << 16) | c);
1756uint QXmlStreamReaderPrivate::getChar_helper()
1758 constexpr qsizetype BUFFER_SIZE = 8192;
1759 characterOffset += readBufferPos;
1761 if (readBuffer.size())
1762 readBuffer.resize(0);
1763 if (decoder.isValid())
1766 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1767 if (!decoder.isValid()) {
1769 if (nbytesread < 4) {
1773 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1775 encoding = QStringDecoder::Utf8;
1776 decoder = QStringDecoder(*encoding);
1779 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1781 if (lockEncoding && decoder.hasError()) {
1790 rawReadBuffer.resize(BUFFER_SIZE);
1791 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1792 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1799 if (!tryDecodeWithGlobalDecoder())
1801 }
else if (dataInfo.empty()) {
1805 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1812 if (bufAndEnc.encoding == QStringDecoder::System) {
1814 rawReadBuffer += bufAndEnc.buffer;
1816 rawReadBuffer = bufAndEnc.buffer;
1817 nbytesread = rawReadBuffer.size();
1819 if (!tryDecodeWithGlobalDecoder()) {
1821 bool hasError =
true;
1822 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1823 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1824 hasError = chunkDecoder.hasError();
1827 raiseWellFormedError(
1828 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1833 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1834 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1835 readBuffer = chunkDecoder(bufAndEnc.buffer);
1839 readBuffer.reserve(1);
1841 if (readBufferPos < readBuffer.size()) {
1842 ushort c = readBuffer.at(readBufferPos++).unicode();
1850XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1852 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1853 if (namespaceDeclaration.prefix == prefix) {
1854 return namespaceDeclaration.namespaceUri;
1859 if (namespaceProcessing && !prefix.isEmpty())
1860 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1863 return XmlStringRef();
1869 QStringView namespaceUri;
1871 static AttributeName fromXmlAttribute(
const QXmlStreamAttribute &a,
bool nsProcessing)
1874 return {a.name(), a.namespaceUri()};
1876 return {a.qualifiedName(), a.namespaceUri()};
1879 friend bool operator==(
const AttributeName &lhs,
const AttributeName &rhs)
noexcept
1881 return lhs.name == rhs.name
1882 && lhs.namespaceUri == rhs.namespaceUri;
1884 friend size_t qHash(
const AttributeName &key, size_t seed = 0)
noexcept
1886 return qHashMulti(seed,
1893
1894
1895void QXmlStreamReaderPrivate::resolveTag()
1897 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1898 const qsizetype n = attributeStack.size();
1900 if (namespaceProcessing) {
1901 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1902 if (!dtdAttribute.isNamespaceAttribute
1903 || dtdAttribute.defaultValue.isNull()
1904 || dtdAttribute.tagName != qualifiedName
1905 || dtdAttribute.attributeQualifiedName.isNull())
1908 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1912 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1913 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1914 namespaceDeclaration.prefix.clear();
1916 const XmlStringRef ns(dtdAttribute.defaultValue);
1917 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1918 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1919 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1921 namespaceDeclaration.namespaceUri = ns;
1922 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1923 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1924 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1925 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1926 if (((namespacePrefix ==
"xml"_L1)
1927 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1928 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1929 || namespaceUri.isEmpty()
1930 || namespacePrefix ==
"xmlns"_L1)
1931 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1933 namespaceDeclaration.prefix = namespacePrefix;
1934 namespaceDeclaration.namespaceUri = namespaceUri;
1939 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1941 attributes.resize(n);
1943 Q_DECL_UNINITIALIZED
1944 QDuplicateTracker<AttributeName, 13> names(n);
1946 for (qsizetype i = 0; i < n; ++i) {
1947 QXmlStreamAttribute &attribute = attributes[i];
1948 Attribute &attrib = attributeStack[i];
1949 XmlStringRef prefix(symPrefix(attrib.key));
1950 XmlStringRef name(symString(attrib.key));
1951 XmlStringRef qualifiedName(symName(attrib.key));
1952 XmlStringRef value(symString(attrib.value));
1954 attribute.m_name = name;
1955 attribute.m_qualifiedName = qualifiedName;
1956 attribute.m_value = value;
1958 if (!prefix.isEmpty()) {
1959 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1960 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1963 if (names.hasSeen(AttributeName::fromXmlAttribute(attribute, namespaceProcessing))) {
1964 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1969 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1970 if (dtdAttribute.isNamespaceAttribute
1971 || dtdAttribute.defaultValue.isNull()
1972 || dtdAttribute.tagName != qualifiedName
1973 || dtdAttribute.attributeQualifiedName.isNull())
1976 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1983 QXmlStreamAttribute attribute;
1984 attribute.m_name = dtdAttribute.attributeName;
1985 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1986 attribute.m_value = dtdAttribute.defaultValue;
1988 if (!dtdAttribute.attributePrefix.isEmpty()) {
1989 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1990 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1999 if (namespaceProcessing && names.hasSeen(AttributeName::fromXmlAttribute(attribute,
true))) {
2000 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
2004 attribute.m_isDefault =
true;
2005 attributes.append(std::move(attribute));
2009void QXmlStreamReaderPrivate::resolvePublicNamespaces()
2011 const Tag &tag = tagStack.top();
2012 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
2013 publicNamespaceDeclarations.resize(n);
2014 for (qsizetype i = 0; i < n; ++i) {
2015 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
2016 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
2017 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
2018 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
2022void QXmlStreamReaderPrivate::resolveDtd()
2024 publicNotationDeclarations.resize(notationDeclarations.size());
2025 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
2026 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
2027 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
2028 publicNotationDeclaration.m_name = notationDeclaration.name;
2029 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
2030 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
2033 notationDeclarations.clear();
2034 publicEntityDeclarations.resize(entityDeclarations.size());
2035 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
2036 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
2037 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
2038 publicEntityDeclaration.m_name = entityDeclaration.name;
2039 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
2040 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
2041 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
2042 publicEntityDeclaration.m_value = entityDeclaration.value;
2044 entityDeclarations.clear();
2045 parameterEntityHash.clear();
2048uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
2053 if (sym(symbolIndex).c ==
'x')
2054 s = symString(symbolIndex).view().sliced(1).toUInt(&ok, 16);
2056 s = symString(symbolIndex).view().toUInt(&ok, 10);
2058 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
2059 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
2065void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
2069 const char16_t *data = publicId.utf16();
2072 for (i = publicId.size() - 1; i >= 0; --i) {
2074 switch ((c = data[i])) {
2075 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
2076 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
2077 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
2078 case '$':
case '_':
case '%':
case '\'':
case '\"':
2081 if (isAsciiLetterOrNumber(c))
2087 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
2091
2092
2093
2094
2095bool QXmlStreamReaderPrivate::checkStartDocument()
2097 hasCheckedStartDocument =
true;
2099 if (scanString(spell[XML], XML))
2102 type = QXmlStreamReader::StartDocument;
2104 hasCheckedStartDocument =
false;
2105 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2110void QXmlStreamReaderPrivate::startDocument()
2113 if (documentVersion !=
"1.0"_L1) {
2114 if (documentVersion.view().contains(u' '))
2115 err = QXmlStream::tr(
"Invalid XML version string.");
2117 err = QXmlStream::tr(
"Unsupported XML version.");
2119 qsizetype n = attributeStack.size();
2122
2123
2124
2126 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2127 Attribute &attrib = attributeStack[i];
2128 XmlStringRef prefix(symPrefix(attrib.key));
2129 XmlStringRef key(symString(attrib.key));
2130 XmlStringRef value(symString(attrib.value));
2132 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2133 documentEncoding = value;
2136 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2137 if (!QXmlUtils::isEncName(value))
2138 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2140 QByteArray enc = value.toString().toUtf8();
2141 if (!lockEncoding) {
2142 decoder = QStringDecoder(enc.constData());
2143 if (!decoder.isValid()) {
2147 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2148 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2150 decoder = QStringDecoder(QStringDecoder::Utf8);
2151 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2157 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2158 if (!decoder.hasError())
2159 readBuffer = std::move(buf);
2163 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2164 hasStandalone =
true;
2165 if (value ==
"yes"_L1)
2167 else if (value ==
"no"_L1)
2170 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2172 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2177 raiseWellFormedError(err);
2178 attributeStack.clear();
2182void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2184 this->error = error;
2185 errorString = message;
2186 if (errorString.isNull()) {
2187 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2188 errorString = QXmlStream::tr(
"Premature end of document.");
2189 else if (error == QXmlStreamReader::CustomError)
2190 errorString = QXmlStream::tr(
"Invalid document.");
2193 type = QXmlStreamReader::Invalid;
2196void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2198 raiseError(QXmlStreamReader::NotWellFormedError, message);
2201void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2204 raiseError(QXmlStreamReader::NotWellFormedError,
2205 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2209void QXmlStreamReaderPrivate::parseError()
2212 if (token == EOF_SYMBOL) {
2213 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2217 QString error_message;
2218 int ers = state_stack[tos];
2221 if (token != XML_ERROR)
2222 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2223 int k = t_action(ers, tk);
2227 if (nexpected < nmax)
2228 expected[nexpected++] = tk;
2232 if (nexpected && nexpected < nmax) {
2234 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2235 .arg(QLatin1StringView(spell[expected[0]]));
2236 if (nexpected == 2) {
2238 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2239 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2240 }
else if (nexpected > 2) {
2242 for (; s < nexpected - 1; ++s) {
2244 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2245 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2248 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2249 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2251 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2252 .arg(exp_str, QLatin1StringView(spell[token]));
2254 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2257 raiseWellFormedError(error_message);
2260void QXmlStreamReaderPrivate::resume(
int rule) {
2261 resumeReduction = rule;
2262 if (error == QXmlStreamReader::NoError)
2263 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2267
2268
2269
2270qint64 QXmlStreamReader::lineNumber()
const
2272 Q_D(
const QXmlStreamReader);
2273 return d->lineNumber + 1;
2277
2278
2279
2280qint64 QXmlStreamReader::columnNumber()
const
2282 Q_D(
const QXmlStreamReader);
2283 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2287
2288
2289
2290qint64 QXmlStreamReader::characterOffset()
const
2292 Q_D(
const QXmlStreamReader);
2293 return d->characterOffset + d->readBufferPos;
2298
2299
2300QStringView QXmlStreamReader::text()
const
2302 Q_D(
const QXmlStreamReader);
2308
2309
2310
2311
2312
2313QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2315 Q_D(
const QXmlStreamReader);
2316 if (!d->scanDtd && !d->notationDeclarations.isEmpty())
2317 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2318 return d->publicNotationDeclarations;
2323
2324
2325
2326
2327
2328QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2330 Q_D(
const QXmlStreamReader);
2331 if (!d->scanDtd && !d->entityDeclarations.isEmpty())
2332 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2333 return d->publicEntityDeclarations;
2337
2338
2339
2340
2341
2342
2343QStringView QXmlStreamReader::dtdName()
const
2345 Q_D(
const QXmlStreamReader);
2346 if (d->type == QXmlStreamReader::DTD)
2348 return QStringView();
2352
2353
2354
2355
2356
2357
2358QStringView QXmlStreamReader::dtdPublicId()
const
2360 Q_D(
const QXmlStreamReader);
2361 if (d->type == QXmlStreamReader::DTD)
2362 return d->dtdPublicId;
2363 return QStringView();
2367
2368
2369
2370
2371
2372
2373QStringView QXmlStreamReader::dtdSystemId()
const
2375 Q_D(
const QXmlStreamReader);
2376 if (d->type == QXmlStreamReader::DTD)
2377 return d->dtdSystemId;
2378 return QStringView();
2382
2383
2384
2385
2386
2387
2388
2389
2390int QXmlStreamReader::entityExpansionLimit()
const
2392 Q_D(
const QXmlStreamReader);
2393 return d->entityExpansionLimit;
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2415 Q_D(QXmlStreamReader);
2417 qWarning(
"QXmlStreamReader::setEntityExpansionLimit(): "
2418 "limit %d is out of range [1:INT_MAX], clamping to 1.", limit);
2420 d->entityExpansionLimit = (std::max)(limit, 1);
2424
2425
2426
2427
2428
2429
2430
2431
2432QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2434 Q_D(
const QXmlStreamReader);
2435 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2436 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2437 return d->publicNamespaceDeclarations;
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2453 Q_D(QXmlStreamReader);
2454 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2455 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2456 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2460
2461
2462
2463
2464
2465
2466void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2468 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2469 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2492 Q_D(QXmlStreamReader);
2493 if (isStartElement()) {
2495 qsizetype nestingLevel = 1;
2497 switch (readNext()) {
2499 case EntityReference:
2500 result.insert(result.size(), d->text);
2505 case ProcessingInstruction:
2509 if (behaviour == SkipChildElements) {
2510 skipCurrentElement();
2512 }
else if (behaviour == IncludeChildElements) {
2518 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2520 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2524 }
while (nestingLevel);
2531
2532
2533
2534void QXmlStreamReader::raiseError(
const QString& message)
2536 Q_D(QXmlStreamReader);
2537 d->raiseError(CustomError, message);
2541
2542
2543
2544
2545QString QXmlStreamReader::errorString()
const
2547 Q_D(
const QXmlStreamReader);
2548 if (d->type == QXmlStreamReader::Invalid)
2549 return d->errorString;
2554
2555
2556
2557QXmlStreamReader::Error QXmlStreamReader::error()
const
2559 Q_D(
const QXmlStreamReader);
2560 if (d->type == QXmlStreamReader::Invalid)
2566
2567
2568QStringView QXmlStreamReader::processingInstructionTarget()
const
2570 Q_D(
const QXmlStreamReader);
2571 return d->processingInstructionTarget;
2575
2576
2577QStringView QXmlStreamReader::processingInstructionData()
const
2579 Q_D(
const QXmlStreamReader);
2580 return d->processingInstructionData;
2586
2587
2588
2589
2590QStringView QXmlStreamReader::name()
const
2592 Q_D(
const QXmlStreamReader);
2597
2598
2599
2600
2601QStringView QXmlStreamReader::namespaceUri()
const
2603 Q_D(
const QXmlStreamReader);
2604 return d->namespaceUri;
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619QStringView QXmlStreamReader::qualifiedName()
const
2621 Q_D(
const QXmlStreamReader);
2622 return d->qualifiedName;
2628
2629
2630
2631
2632
2633
2634QStringView QXmlStreamReader::prefix()
const
2636 Q_D(
const QXmlStreamReader);
2641
2642
2643QXmlStreamAttributes QXmlStreamReader::attributes()
const
2645 Q_D(
const QXmlStreamReader);
2646 return d->attributes;
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2669
2670
2671QXmlStreamAttribute::QXmlStreamAttribute()
2673 m_isDefault =
false;
2677
2678
2679
2680
2681QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2682 : m_isDefault(
false)
2684 m_namespaceUri = namespaceUri;
2685 m_name = m_qualifiedName = name;
2690
2691
2692
2693
2694QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2695 : m_isDefault(
false)
2697 qsizetype colon = qualifiedName.indexOf(u':');
2698 m_name = qualifiedName.mid(colon + 1);
2699 m_qualifiedName = qualifiedName;
2704
2705
2706
2707
2709
2710
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2723
2724
2725
2726
2727
2728
2729
2732
2733
2736
2737
2738
2739
2740
2742
2743
2744
2745
2747
2748
2749
2750
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2775
2776
2777
2778
2781
2782
2783
2784
2785
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2803
2804
2805QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2810
2811
2812
2814
2815
2816
2818
2819
2820
2823
2824
2825
2826
2828
2829
2830
2831
2834
2835
2836
2837
2838
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2854
2855
2856
2857
2859
2860
2861
2862
2865
2866
2867QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2872
2873
2874
2875
2876QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2879 m_namespaceUri = namespaceUri;
2883
2884
2885
2887
2888
2889
2895
2896
2897
2898
2899
2902
2903
2904
2905
2906
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2923
2924
2925QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2930
2931
2932
2934
2935
2936
2938
2939
2940
2942
2943
2944
2946
2947
2948
2951
2952
2953
2954
2956
2957
2958
2959
2962
2963
2964
2965
2966
2967
2968QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2970 for (
const QXmlStreamAttribute &attribute : *
this) {
2971 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2972 return attribute.value();
2974 return QStringView();
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2995 for (
const QXmlStreamAttribute &attribute : *
this) {
2996 if (attribute.qualifiedName() == qualifiedName)
2997 return attribute.value();
2999 return QStringView();
3003
3004
3005
3006void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
3008 append(QXmlStreamAttribute(namespaceUri, name, value));
3012
3013
3014
3015void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
3017 append(QXmlStreamAttribute(qualifiedName, value));
3020#if QT_CONFIG(xmlstreamreader)
3023
3024
3026
3027
3029
3030
3032
3033
3035
3036
3037
3038
3040
3041
3043
3044
3046
3047
3049
3050
3053
3054
3055
3056
3057bool QXmlStreamReader::isWhitespace()
const
3059 Q_D(
const QXmlStreamReader);
3060 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
3064
3065
3066
3067
3068bool QXmlStreamReader::isCDATA()
const
3070 Q_D(
const QXmlStreamReader);
3071 return d->type == QXmlStreamReader::Characters && d->isCDATA;
3077
3078
3079
3080
3081
3082
3083
3084bool QXmlStreamReader::isStandaloneDocument()
const
3086 Q_D(
const QXmlStreamReader);
3087 return d->standalone;
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100bool QXmlStreamReader::hasStandaloneDeclaration()
const
3102 Q_D(
const QXmlStreamReader);
3103 return d->hasStandalone;
3107
3108
3109
3110
3111
3112
3113QStringView QXmlStreamReader::documentVersion()
const
3115 Q_D(
const QXmlStreamReader);
3116 if (d->type == QXmlStreamReader::StartDocument)
3117 return d->documentVersion;
3118 return QStringView();
3122
3123
3124
3125
3126
3127
3128QStringView QXmlStreamReader::documentEncoding()
const
3130 Q_D(
const QXmlStreamReader);
3131 if (d->type == QXmlStreamReader::StartDocument)
3132 return d->documentEncoding;
3133 return QStringView();
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
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3254#if QT_CONFIG(xmlstreamwriter)
3256class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3258 QXmlStreamWriter *q_ptr;
3259 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3261 enum class StartElementOption {
3263 OmitNamespaceDeclarations = 1,
3266 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3267 ~QXmlStreamWriterPrivate() {
3272 void raiseError(QXmlStreamWriter::Error error);
3273 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3274 void write(QAnyStringView s);
3275 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3276 bool finishStartElement(
bool contents =
true);
3277 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3278 StartElementOption option = StartElementOption::KeepEverything);
3279 QIODevice *device =
nullptr;
3280 QString *stringDevice =
nullptr;
3281 uint deleteDevice :1;
3282 uint inStartElement :1;
3283 uint inEmptyElement :1;
3284 uint lastWasStartElement :1;
3285 uint wroteSomething :1;
3286 uint autoFormatting :1;
3287 uint didWriteStartDocument :1;
3288 uint didWriteAnyToken :1;
3289 uint stopWritingOnError :1;
3290 std::string autoFormattingIndent = std::string(4,
' ');
3291 NamespaceDeclaration emptyNamespace;
3292 qsizetype lastNamespaceDeclaration = 1;
3293 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3294 QString errorString;
3296 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3297 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3298 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3300 int namespacePrefixCount = 0;
3302 void indent(
int level);
3304 void doWriteToDevice(QStringView s);
3305 void doWriteToDevice(QUtf8StringView s);
3306 void doWriteToDevice(QLatin1StringView s);
3310QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3311 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3312 inEmptyElement(
false), lastWasStartElement(
false),
3313 wroteSomething(
false), autoFormatting(
false),
3314 didWriteStartDocument(
false), didWriteAnyToken(
false),
3315 stopWritingOnError(
false)
3319void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3323 case QXmlStreamWriter::Error::IO:
3324 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3326 case QXmlStreamWriter::Error::Encoding:
3327 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3329 case QXmlStreamWriter::Error::InvalidCharacter:
3330 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3332 case QXmlStreamWriter::Error::Custom:
3333 errorString = QXmlStream::tr(
"An error occurred while writing");
3335 case QXmlStreamWriter::Error::None:
3336 errorString.clear();
3341void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3344 errorString = message.toString();
3347void QXmlStreamWriterPrivate::write(QAnyStringView s)
3349 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3352 if (error == QXmlStreamWriter::Error::IO)
3355 s.visit([&] (
auto s) { doWriteToDevice(s); });
3356 }
else if (stringDevice) {
3357 s.visit([&] (
auto s) { stringDevice->append(s); });
3359 qWarning(
"QXmlStreamWriter: No device");
3363void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3370 NextResult operator()(
const char *&it,
const char *)
const
3371 {
return {uchar(*it++),
false}; }
3374 NextResult operator()(
const char *&it,
const char *end)
const
3378 constexpr char32_t invalidValue = 0xFFFFFFFF;
3379 static_assert(invalidValue > QChar::LastValidCodePoint);
3380 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3381 const auto old_i = i;
3382 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3383 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3385 return result == invalidValue ? NextResult{U'\0',
true}
3386 : NextResult{result,
false};
3390 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3392 QStringIterator decoder(it, end);
3395 constexpr char32_t invalidValue = 0xFFFFFFFF;
3396 static_assert(invalidValue > QChar::LastValidCodePoint);
3397 char32_t result = decoder.next(invalidValue);
3398 it = decoder.position();
3399 return result == invalidValue ? NextResult{U'\0',
true}
3400 : NextResult{result,
false};
3405 escaped.reserve(s.size());
3406 s.visit([&] (
auto s) {
3407 using View =
decltype(s);
3408 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3409 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3411 auto it = s.begin();
3412 const auto end = s.end();
3416 QLatin1StringView replacement;
3421 const auto decoded = decoder(next_it, end);
3422 switch (decoded.value) {
3424 replacement =
"<"_L1;
3427 replacement =
">"_L1;
3430 replacement =
"&"_L1;
3433 replacement =
"""_L1;
3436 if (escapeWhitespace)
3437 replacement =
"	"_L1;
3440 if (escapeWhitespace)
3441 replacement =
" "_L1;
3444 if (escapeWhitespace)
3445 replacement =
" "_L1;
3449 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3450 if (stopWritingOnError)
3452 replacement =
""_L1;
3453 Q_ASSERT(!replacement.isNull());
3456 if (decoded.value > 0x1F)
3462 raiseError(decoded.encodingError
3463 ? QXmlStreamWriter::Error::Encoding
3464 : QXmlStreamWriter::Error::InvalidCharacter);
3465 if (stopWritingOnError)
3467 replacement =
""_L1;
3468 Q_ASSERT(!replacement.isNull());
3471 if (!replacement.isNull())
3476 escaped.append(View{mark, it});
3477 escaped.append(replacement);
3486void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3487 if (namespaceDeclaration.prefix.isEmpty()) {
3489 write(namespaceDeclaration.namespaceUri);
3493 write(namespaceDeclaration.prefix);
3495 write(namespaceDeclaration.namespaceUri);
3498 didWriteAnyToken =
true;
3501bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3503 bool hadSomethingWritten = wroteSomething;
3504 wroteSomething = contents;
3505 if (!inStartElement)
3506 return hadSomethingWritten;
3508 if (inEmptyElement) {
3510 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3511 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3512 lastWasStartElement =
false;
3516 inStartElement = inEmptyElement =
false;
3517 lastNamespaceDeclaration = namespaceDeclarations.size();
3518 didWriteAnyToken =
true;
3519 return hadSomethingWritten;
3522QXmlStreamPrivateTagStack::NamespaceDeclaration &
3523QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3525 const bool prefixIsXml = prefix ==
"xml"_L1;
3526 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3527 if (prefixIsXml && !namespaceUriIsXml) {
3528 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3529 "than 'http://www.w3.org/XML/1998/namespace'");
3530 }
else if (!prefixIsXml && namespaceUriIsXml) {
3531 const QString prefixString = prefix.toString();
3532 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3533 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3534 qUtf16Printable(prefixString));
3536 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3537 const QString prefixString = prefix.toString();
3538 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3539 "'http://www.w3.org/2000/xmlns/'",
3540 qUtf16Printable(prefixString));
3542 auto &namespaceDeclaration = namespaceDeclarations.push();
3543 namespaceDeclaration.prefix = addToStringStorage(prefix);
3544 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3545 return namespaceDeclaration;
3548QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3550 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3551 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3552 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3553 return namespaceDeclaration;
3556 if (namespaceUri.isEmpty())
3557 return emptyNamespace;
3558 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3559 if (namespaceUri.isEmpty()) {
3560 namespaceDeclaration.prefix.clear();
3563 int n = ++namespacePrefixCount;
3565 s = u'n' + QString::number(n++);
3566 qsizetype j = namespaceDeclarations.size() - 2;
3567 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3572 namespaceDeclaration.prefix = addToStringStorage(s);
3574 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3575 if (writeDeclaration)
3576 writeNamespaceDeclaration(namespaceDeclaration);
3577 return namespaceDeclaration;
3582void QXmlStreamWriterPrivate::indent(
int level)
3584 if (didWriteStartDocument || didWriteAnyToken)
3586 for (
int i = 0; i < level; ++i)
3587 write(autoFormattingIndent);
3590void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3592 constexpr qsizetype MaxChunkSize = 512;
3593 char buffer [3 * MaxChunkSize];
3594 QStringEncoder::State state;
3595 while (!s.isEmpty()) {
3596 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3597 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3598 doWriteToDevice(QUtf8StringView{buffer, end});
3599 s = s.sliced(chunkSize);
3601 if (state.remainingChars > 0)
3602 raiseError(QXmlStreamWriter::Error::Encoding);
3605void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3607 QByteArrayView bytes = s;
3608 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3609 raiseError(QXmlStreamWriter::Error::IO);
3612void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3614 constexpr qsizetype MaxChunkSize = 512;
3615 char buffer [2 * MaxChunkSize];
3616 while (!s.isEmpty()) {
3617 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3618 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3619 doWriteToDevice(QUtf8StringView{buffer, end});
3620 s = s.sliced(chunkSize);
3625
3626
3627
3628
3629QXmlStreamWriter::QXmlStreamWriter()
3630 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3635
3636
3637QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3638 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3640 Q_D(QXmlStreamWriter);
3645
3646
3647
3648QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3649 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3651 Q_D(QXmlStreamWriter);
3652 d->device =
new QBuffer(array);
3653 d->device->open(QIODevice::WriteOnly);
3654 d->deleteDevice =
true;
3659
3660QXmlStreamWriter::QXmlStreamWriter(QString *string)
3661 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3663 Q_D(QXmlStreamWriter);
3664 d->stringDevice = string;
3668
3669
3670QXmlStreamWriter::~QXmlStreamWriter()
3676
3677
3678
3679
3680
3681void QXmlStreamWriter::setDevice(QIODevice *device)
3683 Q_D(QXmlStreamWriter);
3684 if (device == d->device)
3686 d->stringDevice =
nullptr;
3687 if (d->deleteDevice) {
3689 d->deleteDevice =
false;
3695
3696
3697
3698
3699
3700QIODevice *QXmlStreamWriter::device()
const
3702 Q_D(
const QXmlStreamWriter);
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3723
3724
3725
3726
3727
3728
3729
3730void QXmlStreamWriter::setAutoFormatting(
bool enable)
3732 Q_D(QXmlStreamWriter);
3733 d->autoFormatting = enable;
3737
3738
3739
3740
3741bool QXmlStreamWriter::autoFormatting()
const
3743 Q_D(
const QXmlStreamWriter);
3744 return d->autoFormatting;
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3761void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3763 Q_D(QXmlStreamWriter);
3764 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3767int QXmlStreamWriter::autoFormattingIndent()
const
3769 Q_D(
const QXmlStreamWriter);
3770 const QLatin1StringView indent(d->autoFormattingIndent);
3771 return indent.count(u' ') - indent.count(u'\t');
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791bool QXmlStreamWriter::stopWritingOnError()
const
3793 Q_D(
const QXmlStreamWriter);
3794 return d->stopWritingOnError;
3797void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3799 Q_D(QXmlStreamWriter);
3800 d->stopWritingOnError = stop;
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815bool QXmlStreamWriter::hasError()
const
3817 return error() != QXmlStreamWriter::Error::None;
3821
3822
3823
3824
3825
3826
3827
3828
3829QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3831 Q_D(
const QXmlStreamWriter);
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845QString QXmlStreamWriter::errorString()
const
3847 Q_D(
const QXmlStreamWriter);
3848 return d->errorString;
3852
3853
3854
3855
3856
3857
3858
3859
3860void QXmlStreamWriter::raiseError(QAnyStringView message)
3862 Q_D(QXmlStreamWriter);
3863 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3879 Q_D(QXmlStreamWriter);
3880 Q_ASSERT(d->inStartElement);
3881 Q_ASSERT(count(qualifiedName,
':') <= 1);
3883 d->write(qualifiedName);
3885 d->writeEscaped(value,
true);
3887 d->didWriteAnyToken =
true;
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3903 Q_D(QXmlStreamWriter);
3904 Q_ASSERT(d->inStartElement);
3905 Q_ASSERT(!contains(name,
':'));
3906 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3908 if (!namespaceDeclaration.prefix.isEmpty()) {
3909 d->write(namespaceDeclaration.prefix);
3914 d->writeEscaped(value,
true);
3916 d->didWriteAnyToken =
true;
3920
3921
3922
3923
3924
3925
3926
3927void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3929 if (attribute.namespaceUri().isEmpty())
3930 writeAttribute(attribute.qualifiedName(), attribute.value());
3932 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3937
3938
3939
3940
3941
3942
3943
3944
3945void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3947 Q_D(QXmlStreamWriter);
3948 Q_ASSERT(d->inStartElement);
3950 for (
const auto &attr : attributes)
3951 writeAttribute(attr);
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3968 Q_D(QXmlStreamWriter);
3969 d->finishStartElement();
3970 d->write(
"<![CDATA[");
3971 while (!text.isEmpty()) {
3972 const auto idx = indexOf(text,
"]]>"_L1);
3975 d->write(text.first(idx));
3979 text = text.sliced(idx + 3);
3987
3988
3989
3990
3991
3992
3993
3994
3995void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3997 Q_D(QXmlStreamWriter);
3998 d->finishStartElement();
3999 d->writeEscaped(text);
4004
4005
4006
4007
4008
4009
4010void QXmlStreamWriter::writeComment(QAnyStringView text)
4012 Q_D(QXmlStreamWriter);
4013 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
4014 if (!d->finishStartElement(
false) && d->autoFormatting)
4015 d->indent(d->tagStack.size());
4019 d->inStartElement = d->lastWasStartElement =
false;
4024
4025
4026
4027
4028
4029void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
4031 Q_D(QXmlStreamWriter);
4032 d->finishStartElement();
4033 if (d->autoFormatting)
4036 if (d->autoFormatting)
4043
4044
4045
4046
4047
4048
4049void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
4051 Q_D(QXmlStreamWriter);
4052 Q_ASSERT(count(qualifiedName,
':') <= 1);
4053 d->writeStartElement({}, qualifiedName);
4054 d->inEmptyElement =
true;
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
4070 Q_D(QXmlStreamWriter);
4071 Q_ASSERT(!contains(name,
':'));
4072 d->writeStartElement(namespaceUri, name);
4073 d->inEmptyElement =
true;
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
4089 writeStartElement(qualifiedName);
4090 writeCharacters(text);
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
4108 writeStartElement(namespaceUri, name);
4109 writeCharacters(text);
4115
4116
4117
4118
4119void QXmlStreamWriter::writeEndDocument()
4121 Q_D(QXmlStreamWriter);
4122 while (d->tagStack.size())
4124 if (d->didWriteStartDocument || d->didWriteAnyToken)
4129
4130
4131
4132
4133void QXmlStreamWriter::writeEndElement()
4135 Q_D(QXmlStreamWriter);
4136 Q_ASSERT(d->didWriteAnyToken);
4137 if (d->tagStack.isEmpty())
4141 if (d->inStartElement && !d->inEmptyElement) {
4143 d->lastWasStartElement = d->inStartElement =
false;
4144 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4145 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4149 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4150 d->indent(d->tagStack.size()-1);
4151 if (d->tagStack.isEmpty())
4153 d->lastWasStartElement =
false;
4154 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4155 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4157 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4158 d->write(tag.namespaceDeclaration.prefix);
4168
4169
4170
4171
4172
4173void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4175 Q_D(QXmlStreamWriter);
4176 d->finishStartElement();
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4202 Q_D(QXmlStreamWriter);
4203 Q_ASSERT(prefix !=
"xmlns"_L1);
4204 if (prefix.isEmpty()) {
4205 d->findNamespace(namespaceUri, d->inStartElement);
4207 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4208 if (d->inStartElement)
4209 d->writeNamespaceDeclaration(namespaceDeclaration);
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4229 Q_D(QXmlStreamWriter);
4230 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4231 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4232 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4233 namespaceDeclaration.prefix.clear();
4234 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4235 if (d->inStartElement)
4236 d->writeNamespaceDeclaration(namespaceDeclaration);
4241
4242
4243
4244
4245
4246
4247void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4249 Q_D(QXmlStreamWriter);
4250 Q_ASSERT(!contains(data,
"?>"_L1));
4251 if (!d->finishStartElement(
false) && d->autoFormatting)
4252 d->indent(d->tagStack.size());
4255 if (!data.isNull()) {
4260 d->didWriteAnyToken =
true;
4266
4267
4268
4269
4270
4271
4272void QXmlStreamWriter::writeStartDocument()
4274 writeStartDocument(
"1.0"_L1);
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4296 Q_D(QXmlStreamWriter);
4297 d->finishStartElement(
false);
4298 d->write(
"<?xml version=\"");
4301 d->write(
"\" encoding=\"UTF-8");
4303 d->didWriteStartDocument =
true;
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4326 Q_D(QXmlStreamWriter);
4327 d->finishStartElement(
false);
4328 d->write(
"<?xml version=\"");
4331 d->write(
"\" encoding=\"UTF-8");
4333 d->write(
"\" standalone=\"yes\"?>");
4335 d->write(
"\" standalone=\"no\"?>");
4336 d->didWriteStartDocument =
true;
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4352 Q_D(QXmlStreamWriter);
4353 Q_ASSERT(count(qualifiedName,
':') <= 1);
4354 d->writeStartElement({}, qualifiedName);
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4371 Q_D(QXmlStreamWriter);
4372 Q_ASSERT(!contains(name,
':'));
4373 d->writeStartElement(namespaceUri, name);
4376void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4377 StartElementOption option)
4379 if (!finishStartElement(
false) && autoFormatting)
4380 indent(tagStack.size());
4382 Tag &tag = tagStack_push();
4383 tag.name = addToStringStorage(name);
4384 tag.namespaceDeclaration = findNamespace(namespaceUri);
4386 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4387 write(tag.namespaceDeclaration.prefix);
4391 inStartElement = lastWasStartElement =
true;
4393 if (option != StartElementOption::OmitNamespaceDeclarations) {
4394 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4395 writeNamespaceDeclaration(namespaceDeclarations[i]);
4397 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4398 didWriteAnyToken =
true;
4401#if QT_CONFIG(xmlstreamreader)
4403
4404
4405
4406
4407
4408
4409void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4411 Q_D(QXmlStreamWriter);
4412 switch (reader.tokenType()) {
4413 case QXmlStreamReader::NoToken:
4415 case QXmlStreamReader::StartDocument:
4416 writeStartDocument();
4418 case QXmlStreamReader::EndDocument:
4421 case QXmlStreamReader::StartElement: {
4423 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4424 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4425 for (
const auto &namespaceDeclaration : nsDeclarations) {
4426 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4427 namespaceDeclaration.prefix());
4428 extraNamespaces.append(extraNamespace);
4430 d->writeStartElement(
4431 reader.namespaceUri(), reader.name(),
4432 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4434 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4435 d->writeNamespaceDeclaration(extraNamespace);
4436 writeAttributes(reader.attributes());
4438 case QXmlStreamReader::EndElement:
4441 case QXmlStreamReader::Characters:
4442 if (reader.isCDATA())
4443 writeCDATA(reader.text());
4445 writeCharacters(reader.text());
4447 case QXmlStreamReader::Comment:
4448 writeComment(reader.text());
4450 case QXmlStreamReader::DTD:
4451 writeDTD(reader.text());
4453 case QXmlStreamReader::EntityReference:
4454 writeEntityReference(reader.name());
4456 case QXmlStreamReader::ProcessingInstruction:
4457 writeProcessingInstruction(reader.processingInstructionTarget(),
4458 reader.processingInstructionData());
4461 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4462 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4469#if QT_CONFIG(xmlstreamreader)
4470static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4471 QXmlStreamReaderPrivate::XmlContext ctxt)
4474 case QXmlStreamReader::StartDocument:
4475 case QXmlStreamReader::DTD:
4476 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4478 case QXmlStreamReader::StartElement:
4479 case QXmlStreamReader::EndElement:
4480 case QXmlStreamReader::Characters:
4481 case QXmlStreamReader::EntityReference:
4482 case QXmlStreamReader::EndDocument:
4483 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4485 case QXmlStreamReader::Comment:
4486 case QXmlStreamReader::ProcessingInstruction:
4489 case QXmlStreamReader::NoToken:
4490 case QXmlStreamReader::Invalid:
4495#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4496 Q_UNREACHABLE_RETURN(
false);
4503
4504
4505
4506
4507
4508
4509bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4512 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4516 const bool result = isTokenAllowedInContext(type, currentContext);
4517 if (result || currentContext == XmlContext::Body)
4521 currentContext = XmlContext::Body;
4522 return isTokenAllowedInContext(type, currentContext);
4526
4527
4528
4529
4530void QXmlStreamReaderPrivate::checkToken()
4532 Q_Q(QXmlStreamReader);
4535 const XmlContext context = currentContext;
4536 const bool ok = isValidToken(type);
4539 if (error != QXmlStreamReader::Error::NoError)
4543 raiseError(QXmlStreamReader::UnexpectedElementError,
4544 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4545 .arg(q->tokenString(), contextString(context)));
4549 if (type != QXmlStreamReader::DTD)
4554 raiseError(QXmlStreamReader::UnexpectedElementError,
4555 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4576
4577
4578
4579
4580
4581
4582
4583