5#include "QtCore/qxmlstream.h"
7#if QT_CONFIG(xmlstream)
9#include "qxmlutils_p.h"
13#include <qstringconverter.h>
16#include <qscopeguard.h>
17#include <qcoreapplication.h>
19#include <private/qoffsetstringarray_p.h>
20#include <private/qtools_p.h>
23#include "qxmlstream_p.h"
24#include "qxmlstreamparser_p.h"
25#include <private/qstringconverter_p.h>
26#include <private/qstringiterator_p.h>
30using namespace QtPrivate;
31using namespace Qt::StringLiterals;
32using namespace QtMiscUtils;
34constexpr uint StreamEOF = ~0U;
37template <
typename Range>
38auto reversed(Range &r)
42 auto begin() {
return std::make_reverse_iterator(std::end(*r)); }
43 auto end() {
return std::make_reverse_iterator(std::begin(*r)); }
49template <
typename Range>
50void reversed(
const Range &&) =
delete;
53auto transform(QLatin1StringView haystack,
char needle)
55 struct R { QLatin1StringView haystack;
char16_t needle; };
56 return R{haystack, uchar(needle)};
59auto transform(QStringView haystack,
char needle)
61 struct R { QStringView haystack;
char16_t needle; };
62 return R{haystack, uchar(needle)};
65auto transform(QUtf8StringView haystack,
char needle)
67 struct R { QByteArrayView haystack;
char needle; };
68 return R{haystack, needle};
71auto transform(QLatin1StringView haystack, QLatin1StringView needle)
73 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
74 return R{haystack, needle};
77auto transform(QStringView haystack, QLatin1StringView needle)
79 struct R { QStringView haystack; QLatin1StringView needle; };
80 return R{haystack, needle};
83auto transform(QUtf8StringView haystack, QLatin1StringView needle)
85 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
86 return R{QLatin1StringView{QByteArrayView{haystack}}, needle};
89#define WRAP(method, Needle)
90 auto method (QAnyStringView s, Needle needle) noexcept
92 return s.visit([needle](auto s) {
93 auto r = transform(s, needle);
94 return r.haystack. method (r.needle);
101WRAP(contains, QLatin1StringView)
103WRAP(indexOf, QLatin1StringView)
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
157
158
159
160
161
162
163
164
165
166
167
168
169
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
195
196
197
198
199
200
201
202
203
204
207
208
209QXmlStreamEntityResolver::~QXmlStreamEntityResolver()
214
215
216
217
218QString QXmlStreamEntityResolver::resolveEntity(
const QString& ,
const QString& )
225
226
227
228
229
230
232QString QXmlStreamEntityResolver::resolveUndeclaredEntity(
const QString &)
237#if QT_CONFIG(xmlstreamreader)
239QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(
const QString &name)
242 return entityResolver->resolveUndeclaredEntity(name);
249
250
251
252
253
254
255
256
257
258
259
260void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
262 Q_D(QXmlStreamReader);
263 d->entityResolver = resolver;
267
268
269
270
271
272
273QXmlStreamEntityResolver *QXmlStreamReader::entityResolver()
const
275 Q_D(
const QXmlStreamReader);
276 return d->entityResolver;
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
429
430
431
432
433QXmlStreamReader::QXmlStreamReader()
434 : d_ptr(
new QXmlStreamReaderPrivate(
this))
439
440
441
442QXmlStreamReader::QXmlStreamReader(QIODevice *device)
443 : d_ptr(
new QXmlStreamReaderPrivate(
this))
449
450
451
452
453
454
455
456
459
460
461
462
463
464
465
466
467
468void QXmlStreamReaderPrivate::appendDataWithEncoding(
const QByteArray &data,
469 QStringDecoder::Encoding enc)
475 if (!dataInfo.empty()) {
476 auto &last = dataInfo.last();
477 if (last.encoding == enc) {
478 last.buffer.append(data);
482 dataInfo.emplace_back(data, enc);
485void QXmlStreamReaderPrivate::addData(
const QByteArray &data, QStringDecoder::Encoding enc)
488 qWarning(
"QXmlStreamReader: addData() with device()");
491 appendDataWithEncoding(data, enc);
495
496
497
498
499
500
501
502QXmlStreamReader::QXmlStreamReader(QAnyStringView data)
503 : d_ptr(
new QXmlStreamReaderPrivate(
this))
505 Q_D(QXmlStreamReader);
506 data.visit([d](
auto data) {
507 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
508 d->appendDataWithEncoding(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
510 QStringDecoder::Utf16);
511 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
512 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
513 QStringDecoder::Latin1);
515 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
516 QStringDecoder::Utf8);
522
523
524
525
526
527QXmlStreamReader::QXmlStreamReader(
const QByteArray &data, PrivateConstructorTag)
528 : d_ptr(
new QXmlStreamReaderPrivate(
this))
530 Q_D(QXmlStreamReader);
531 d->appendDataWithEncoding(data, QStringDecoder::System);
535
536
537QXmlStreamReader::~QXmlStreamReader()
539 Q_D(QXmlStreamReader);
545
546
547
548
551
552
553
554
555
556void QXmlStreamReader::setDevice(QIODevice *device)
558 Q_D(QXmlStreamReader);
559 if (d->deleteDevice) {
561 d->deleteDevice =
false;
569
570
571
572
573
574QIODevice *QXmlStreamReader::device()
const
576 Q_D(
const QXmlStreamReader);
581
582
583
584
585
586
587
588
589
591static bool isDecoderForEncoding(
const QStringDecoder &dec, QStringDecoder::Encoding enc)
596 const QAnyStringView nameView{dec.name()};
597 return !nameView.empty() && nameView == QStringDecoder::nameForEncoding(enc);
601
602
603
604
605
606
607
608
609void QXmlStreamReader::addData(QAnyStringView data)
611 Q_D(QXmlStreamReader);
612 data.visit([d](
auto data) {
613 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
614 d->addData(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
616 QStringDecoder::Utf16);
617 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
618 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Latin1);
620 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Utf8);
626
627
628
629
630
631void QXmlStreamReader::addDataImpl(
const QByteArray &data)
633 Q_D(QXmlStreamReader);
634 d->addData(data, QStringDecoder::System);
638
639
640
641
642
643void QXmlStreamReader::clear()
645 Q_D(QXmlStreamReader);
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669bool QXmlStreamReader::atEnd()
const
671 Q_D(
const QXmlStreamReader);
673 && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError)
674 || (d->type == QXmlStreamReader::EndDocument))) {
676 return d->device->atEnd();
678 return d->dataInfo.empty();
680 return (d->atEnd || d->type == QXmlStreamReader::Invalid);
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702QXmlStreamReader::TokenType QXmlStreamReader::readNext()
704 Q_D(QXmlStreamReader);
705 if (d->type != Invalid) {
706 if (!d->hasCheckedStartDocument)
707 if (!d->checkStartDocument())
710 if (d->atEnd && d->type != EndDocument && d->type != Invalid)
711 d->raiseError(PrematureEndOfDocumentError);
712 else if (!d->atEnd && d->type == EndDocument)
713 d->raiseWellFormedError(QXmlStream::tr(
"Extra content at end of document."));
714 }
else if (d->error == PrematureEndOfDocumentError) {
727
728
729
730
731
732
733
734
735
736QXmlStreamReader::TokenType QXmlStreamReader::tokenType()
const
738 Q_D(
const QXmlStreamReader);
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759bool QXmlStreamReader::readNextStartElement()
761 while (readNext() != Invalid) {
762 if (isEndElement() || isEndDocument())
764 else if (isStartElement())
771
772
773
774
775
776
777
778
779
780
781void QXmlStreamReader::skipCurrentElement()
784 while (depth && readNext() != Invalid) {
787 else if (isStartElement())
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811QString QXmlStreamReader::readRawInnerData()
813 Q_D(QXmlStreamReader);
816 auto specialToEntities = [](QStringView text, QString &output) {
818 QLatin1StringView replacement;
819 const qsizetype sz = text.size();
820 for (qsizetype i = 0; i < sz; ++i) {
821 switch (text[i].unicode()) {
823 replacement =
"<"_L1;
826 replacement =
">"_L1;
829 replacement =
"&"_L1;
832 replacement =
"""_L1;
835 replacement =
"'"_L1;
841 output += text.mid(chunk, i - chunk);
842 output += replacement;
845 if (chunk < text.size())
846 output += text.mid(chunk);
849 if (isStartElement()) {
851 while (!atEnd() && depth) {
852 switch (readNext()) {
854 raw +=
'<'_L1 + name();
855 const QXmlStreamAttributes attrs = attributes();
856 for (
auto it = attrs.begin(); it != attrs.end(); ++it) {
857 raw +=
' '_L1 + it->name() +
"=\""_L1;
858 specialToEntities(it->value(), raw);
868 raw +=
"</"_L1 + name() +
'>'_L1;
872 raw +=
"<![CDATA["_L1 + text() +
"]]>"_L1;
874 specialToEntities(text(), raw);
877 raw +=
"<!--"_L1 + text() +
"-->"_L1;
879 case EntityReference:
880 raw +=
'&'_L1 + name() +
';'_L1;
882 case ProcessingInstruction:
883 raw +=
"<?"_L1 + processingInstructionTarget()
884 +
' '_L1 + processingInstructionData()
890 d->raiseError(NotWellFormedError,
891 QXmlStream::tr(
"Unexpected token while "
892 "reading raw inner data."));
901static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
912 "ProcessingInstruction"
915static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
921
922
923
924
925
926
927
928
929
932void QXmlStreamReader::setNamespaceProcessing(
bool enable)
934 Q_D(QXmlStreamReader);
935 d->namespaceProcessing = enable;
938bool QXmlStreamReader::namespaceProcessing()
const
940 Q_D(
const QXmlStreamReader);
941 return d->namespaceProcessing;
945
946
947
948QString QXmlStreamReader::tokenString()
const
950 Q_D(
const QXmlStreamReader);
951 return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
955
956
957
958static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
960 return QLatin1StringView(QXmlStreamReader_XmlContextString.viewAt(
static_cast<
int>(ctxt)));
965QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
967 tagStack.reserve(16);
968 tagStackStringStorage.reserve(32);
969 tagStackStringStorageSize = 0;
970 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
971 namespaceDeclaration.prefix = addToStringStorage(u"xml");
972 namespaceDeclaration.namespaceUri = addToStringStorage(u"http://www.w3.org/XML/1998/namespace");
973 initialTagStackStringStorageSize = tagStackStringStorageSize;
977#if QT_CONFIG(xmlstreamreader)
979QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
983 deleteDevice =
false;
986 state_stack =
nullptr;
988 entityResolver =
nullptr;
990#define ADD_PREDEFINED(n, v)
992 Entity e = Entity::createLiteral(n##_L1, v##_L1);
993 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e));
995 ADD_PREDEFINED(
"lt",
"<");
996 ADD_PREDEFINED(
"gt",
">");
997 ADD_PREDEFINED(
"amp",
"&");
998 ADD_PREDEFINED(
"apos",
"'");
999 ADD_PREDEFINED(
"quot",
"\"");
1000#undef ADD_PREDEFINED
1003void QXmlStreamReaderPrivate::init()
1006 lastAttributeIsCData =
false;
1009 isEmptyElement =
false;
1010 isWhitespace =
true;
1013 hasStandalone =
false;
1015 resumeReduction = 0;
1016 state_stack[tos++] = 0;
1017 state_stack[tos] = 0;
1019 putStack.reserve(32);
1021 textBuffer.reserve(256);
1025 attributes.reserve(16);
1026 lineNumber = lastLineStart = characterOffset = 0;
1029 decoder = QStringDecoder();
1030 attributeStack.clear();
1031 attributeStack.reserve(16);
1032 entityParser.reset();
1033 hasCheckedStartDocument =
false;
1034 normalizeLiterals =
false;
1037 inParseEntity =
false;
1038 referenceToUnparsedEntityDetected =
false;
1039 referenceToParameterEntityDetected =
false;
1040 hasExternalDtdSubset =
false;
1041 lockEncoding =
false;
1042 namespaceProcessing =
true;
1043 rawReadBuffer.clear();
1044 chunkDecoder = QStringDecoder();
1047 tagStackStringStorageSize = initialTagStackStringStorageSize;
1049 type = QXmlStreamReader::NoToken;
1050 error = QXmlStreamReader::NoError;
1051 currentContext = XmlContext::Prolog;
1056
1057
1058
1059void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1061 Q_Q(QXmlStreamReader);
1063 if (value.isEmpty())
1068 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1070 entityParser->init();
1071 entityParser->inParseEntity =
true;
1072 entityParser->readBuffer = value;
1073 entityParser->injectToken(PARSE_ENTITY);
1074 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1075 entityParser->parse();
1076 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1077 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1081inline void QXmlStreamReaderPrivate::reallocateStack()
1084 void *p = realloc(sym_stack, stack_size *
sizeof(Value));
1086 sym_stack =
static_cast<Value*>(p);
1087 p = realloc(state_stack, stack_size *
sizeof(
int));
1089 state_stack =
static_cast<
int*>(p);
1093QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1100inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1102 uint peekc = peekChar();
1103 if (peekc ==
'\n') {
1104 if (putStack.size())
1110 if (peekc == StreamEOF) {
1118
1119
1120
1121inline uint QXmlStreamReaderPrivate::getChar()
1124 if (putStack.size()) {
1125 c = atEnd ? StreamEOF : putStack.pop();
1127 if (readBufferPos < readBuffer.size())
1128 c = readBuffer.at(readBufferPos++).unicode();
1130 c = getChar_helper();
1136inline uint QXmlStreamReaderPrivate::peekChar()
1139 if (putStack.size()) {
1141 }
else if (readBufferPos < readBuffer.size()) {
1142 c = readBuffer.at(readBufferPos).unicode();
1144 if ((c = getChar_helper()) != StreamEOF)
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1165 const qsizetype pos = textBuffer.size();
1166 const auto oldLineNumber = lineNumber;
1169 while ((c = getChar()) != StreamEOF) {
1173 if ((c = filterCarriageReturn()) == 0)
1178 lastLineStart = characterOffset + readBufferPos;
1181 textBuffer += QChar(c);
1184 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1185 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1186 lineNumber = oldLineNumber;
1189 textBuffer += QChar(c);
1194 if (c == uint(*str)) {
1196 if (tokenToInject >= 0)
1197 injectToken(tokenToInject);
1200 if (scanString(str + 1, tokenToInject,
false))
1205 putString(textBuffer, pos);
1206 textBuffer.resize(pos);
1207 lineNumber = oldLineNumber;
1211bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1216 if (c != ushort(str[n])) {
1220 putChar(ushort(str[n]));
1226 textBuffer += QLatin1StringView(str, n);
1228 const qsizetype s = fastScanSpace();
1230 qsizetype pos = textBuffer.size() - n - s;
1231 putString(textBuffer, pos);
1232 textBuffer.resize(pos);
1236 if (tokenToInject >= 0)
1237 injectToken(tokenToInject);
1241bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1243 switch (peekChar()) {
1245 return scanString(spell[CDATA_START], CDATA_START,
false);
1247 return scanString(spell[DOCTYPE], DOCTYPE);
1249 return scanString(spell[ATTLIST], ATTLIST);
1251 return scanString(spell[NOTATION], NOTATION);
1253 if (scanString(spell[ELEMENT], ELEMENT))
1255 return scanString(spell[ENTITY], ENTITY);
1263bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1265 switch (peekChar()) {
1267 return scanString(spell[SYSTEM], SYSTEM);
1269 return scanString(spell[PUBLIC], PUBLIC);
1276bool QXmlStreamReaderPrivate::scanNData()
1278 if (fastScanSpace()) {
1279 if (scanString(spell[NDATA], NDATA))
1286bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1288 switch (peekChar()) {
1290 return scanString(spell[REQUIRED], REQUIRED,
false);
1292 return scanString(spell[IMPLIED], IMPLIED,
false);
1294 return scanString(spell[FIXED], FIXED,
false);
1301bool QXmlStreamReaderPrivate::scanAttType()
1303 switch (peekChar()) {
1305 return scanString(spell[CDATA], CDATA);
1307 if (scanString(spell[ID], ID))
1309 if (scanString(spell[IDREF], IDREF))
1311 return scanString(spell[IDREFS], IDREFS);
1313 if (scanString(spell[ENTITY], ENTITY))
1315 return scanString(spell[ENTITIES], ENTITIES);
1317 if (scanString(spell[NOTATION], NOTATION))
1319 if (scanString(spell[NMTOKEN], NMTOKEN))
1321 return scanString(spell[NMTOKENS], NMTOKENS);
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1344 while ((c = getChar()) != StreamEOF) {
1345 switch (ushort(c)) {
1350
1354 if (filterCarriageReturn() == 0)
1359 lastLineStart = characterOffset + readBufferPos;
1363 if (normalizeLiterals)
1366 textBuffer += QChar(c);
1373 if (!(c & 0xff0000)) {
1383 textBuffer += QChar(ushort(c));
1390inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1394 while ((c = getChar()) != StreamEOF) {
1397 if ((c = filterCarriageReturn()) == 0)
1402 lastLineStart = characterOffset + readBufferPos;
1406 textBuffer += QChar(c);
1418
1419
1420
1421
1422
1423inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1427 while ((c = getChar()) != StreamEOF) {
1428 switch (ushort(c)) {
1435 isWhitespace =
false;
1436 const qsizetype pos = textBuffer.size();
1437 textBuffer += QChar(ushort(c));
1439 while ((c = getChar()) ==
']') {
1440 textBuffer += QChar(ushort(c));
1443 if (c == StreamEOF) {
1444 putString(textBuffer, pos);
1445 textBuffer.resize(pos);
1446 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1447 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1455 if ((c = filterCarriageReturn()) == 0)
1460 lastLineStart = characterOffset + readBufferPos;
1464 textBuffer += QChar(ushort(c));
1469 if (!(c & 0xff0000)) {
1479 isWhitespace =
false;
1480 textBuffer += QChar(ushort(c));
1488inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1492 while ((c = getChar()) != StreamEOF) {
1496 raiseNamePrefixTooLongError();
1497 return std::nullopt;
1526 if (val && val->prefix == n + 1) {
1534 if (val->prefix == 0) {
1535 val->prefix = qint16(n + 2);
1546 textBuffer += QChar(ushort(c));
1553 qsizetype pos = textBuffer.size() - n;
1554 putString(textBuffer, pos);
1555 textBuffer.resize(pos);
1559enum NameChar { NameBeginning, NameNotBeginning, NotName };
1561static const char Begi =
static_cast<
char>(NameBeginning);
1562static const char NtBg =
static_cast<
char>(NameNotBeginning);
1563static const char NotN =
static_cast<
char>(NotName);
1565static const char nameCharTable[128] =
1568 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1569 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1571 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1572 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1574 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1575 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1577 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1578 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1580 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1581 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1583 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1584 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1586 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1587 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1589 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1590 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1593static inline NameChar fastDetermineNameChar(QChar ch)
1595 ushort uc = ch.unicode();
1597 return static_cast<NameChar>(nameCharTable[uc]);
1599 QChar::Category cat = ch.category();
1601 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1602 || cat == QChar::Number_Letter)
1603 return NameBeginning;
1604 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1605 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1606 return NameNotBeginning;
1610inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1614 while ((c = getChar()) != StreamEOF) {
1615 if (fastDetermineNameChar(QChar(c)) == NotName) {
1620 textBuffer += QChar(c);
1624 qsizetype pos = textBuffer.size() - n;
1625 putString(textBuffer, pos);
1626 textBuffer.resize(pos);
1631void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1634 putString(s.mid(from));
1637 putStack.reserve(s.size());
1638 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1639 putStack.rawPush() = it->unicode();
1642void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1644 putStack.reserve(s.size());
1645 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1646 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1649void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1651 putStack.reserve(s.size());
1652 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1653 char16_t c = it->unicode();
1654 if (c ==
'\n' || c ==
'\r')
1655 putStack.rawPush() = ((LETTER << 16) | c);
1657 putStack.rawPush() = c;
1660void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1662 putStack.reserve(s.size());
1663 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1664 char16_t c = it->unicode();
1665 if (c ==
'&' || c ==
';')
1666 putStack.rawPush() = c;
1667 else if (c ==
'\n' || c ==
'\r')
1668 putStack.rawPush() =
' ';
1670 putStack.rawPush() = ((LETTER << 16) | c);
1674uint QXmlStreamReaderPrivate::getChar_helper()
1676 constexpr qsizetype BUFFER_SIZE = 8192;
1677 characterOffset += readBufferPos;
1679 if (readBuffer.size())
1680 readBuffer.resize(0);
1681 if (decoder.isValid())
1684 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1685 if (!decoder.isValid()) {
1687 if (nbytesread < 4) {
1691 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1693 encoding = QStringDecoder::Utf8;
1694 decoder = QStringDecoder(*encoding);
1697 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1699 if (lockEncoding && decoder.hasError()) {
1708 rawReadBuffer.resize(BUFFER_SIZE);
1709 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1710 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1717 if (!tryDecodeWithGlobalDecoder())
1719 }
else if (dataInfo.empty()) {
1723 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1730 if (bufAndEnc.encoding == QStringDecoder::System) {
1732 rawReadBuffer += bufAndEnc.buffer;
1734 rawReadBuffer = bufAndEnc.buffer;
1735 nbytesread = rawReadBuffer.size();
1737 if (!tryDecodeWithGlobalDecoder()) {
1739 bool hasError =
true;
1740 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1741 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1742 hasError = chunkDecoder.hasError();
1745 raiseWellFormedError(
1746 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1751 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1752 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1753 readBuffer = chunkDecoder(bufAndEnc.buffer);
1757 readBuffer.reserve(1);
1759 if (readBufferPos < readBuffer.size()) {
1760 ushort c = readBuffer.at(readBufferPos++).unicode();
1768XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1770 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1771 if (namespaceDeclaration.prefix == prefix) {
1772 return namespaceDeclaration.namespaceUri;
1777 if (namespaceProcessing && !prefix.isEmpty())
1778 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1781 return XmlStringRef();
1785
1786
1787void QXmlStreamReaderPrivate::resolveTag()
1789 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1790 const qsizetype n = attributeStack.size();
1792 if (namespaceProcessing) {
1793 for (DtdAttribute &dtdAttribute : dtdAttributes) {
1794 if (!dtdAttribute.isNamespaceAttribute
1795 || dtdAttribute.defaultValue.isNull()
1796 || dtdAttribute.tagName != qualifiedName
1797 || dtdAttribute.attributeQualifiedName.isNull())
1800 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1804 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1805 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1806 namespaceDeclaration.prefix.clear();
1808 const XmlStringRef ns(dtdAttribute.defaultValue);
1809 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1810 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1811 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1813 namespaceDeclaration.namespaceUri = ns;
1814 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1815 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1816 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1817 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1818 if (((namespacePrefix ==
"xml"_L1)
1819 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1820 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1821 || namespaceUri.isEmpty()
1822 || namespacePrefix ==
"xmlns"_L1)
1823 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1825 namespaceDeclaration.prefix = namespacePrefix;
1826 namespaceDeclaration.namespaceUri = namespaceUri;
1831 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1833 attributes.resize(n);
1835 for (qsizetype i = 0; i < n; ++i) {
1836 QXmlStreamAttribute &attribute = attributes[i];
1837 Attribute &attrib = attributeStack[i];
1838 XmlStringRef prefix(symPrefix(attrib.key));
1839 XmlStringRef name(symString(attrib.key));
1840 XmlStringRef qualifiedName(symName(attrib.key));
1841 XmlStringRef value(symString(attrib.value));
1843 attribute.m_name = name;
1844 attribute.m_qualifiedName = qualifiedName;
1845 attribute.m_value = value;
1847 if (!prefix.isEmpty()) {
1848 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1849 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1852 for (qsizetype j = 0; j < i; ++j) {
1853 if (attributes[j].name() == attribute.name()
1854 && attributes[j].namespaceUri() == attribute.namespaceUri()
1855 && (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName()))
1857 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1863 for (DtdAttribute &dtdAttribute : dtdAttributes) {
1864 if (dtdAttribute.isNamespaceAttribute
1865 || dtdAttribute.defaultValue.isNull()
1866 || dtdAttribute.tagName != qualifiedName
1867 || dtdAttribute.attributeQualifiedName.isNull())
1870 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1877 QXmlStreamAttribute attribute;
1878 attribute.m_name = dtdAttribute.attributeName;
1879 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1880 attribute.m_value = dtdAttribute.defaultValue;
1882 if (!dtdAttribute.attributePrefix.isEmpty()) {
1883 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1884 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1886 attribute.m_isDefault =
true;
1887 attributes.append(std::move(attribute));
1891void QXmlStreamReaderPrivate::resolvePublicNamespaces()
1893 const Tag &tag = tagStack.top();
1894 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
1895 publicNamespaceDeclarations.resize(n);
1896 for (qsizetype i = 0; i < n; ++i) {
1897 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
1898 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
1899 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
1900 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
1904void QXmlStreamReaderPrivate::resolveDtd()
1906 publicNotationDeclarations.resize(notationDeclarations.size());
1907 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
1908 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
1909 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
1910 publicNotationDeclaration.m_name = notationDeclaration.name;
1911 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
1912 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
1915 notationDeclarations.clear();
1916 publicEntityDeclarations.resize(entityDeclarations.size());
1917 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
1918 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
1919 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
1920 publicEntityDeclaration.m_name = entityDeclaration.name;
1921 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
1922 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
1923 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
1924 publicEntityDeclaration.m_value = entityDeclaration.value;
1926 entityDeclarations.clear();
1927 parameterEntityHash.clear();
1930uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
1935 if (sym(symbolIndex).c ==
'x')
1936 s = symString(symbolIndex, 1).view().toUInt(&ok, 16);
1938 s = symString(symbolIndex).view().toUInt(&ok, 10);
1940 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
1941 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
1947void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
1951 const char16_t *data = publicId.utf16();
1954 for (i = publicId.size() - 1; i >= 0; --i) {
1956 switch ((c = data[i])) {
1957 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
1958 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
1959 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
1960 case '$':
case '_':
case '%':
case '\'':
case '\"':
1963 if (isAsciiLetterOrNumber(c))
1969 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
1973
1974
1975
1976
1977bool QXmlStreamReaderPrivate::checkStartDocument()
1979 hasCheckedStartDocument =
true;
1981 if (scanString(spell[XML], XML))
1984 type = QXmlStreamReader::StartDocument;
1986 hasCheckedStartDocument =
false;
1987 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
1992void QXmlStreamReaderPrivate::startDocument()
1995 if (documentVersion !=
"1.0"_L1) {
1996 if (documentVersion.view().contains(u' '))
1997 err = QXmlStream::tr(
"Invalid XML version string.");
1999 err = QXmlStream::tr(
"Unsupported XML version.");
2001 qsizetype n = attributeStack.size();
2004
2005
2006
2008 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2009 Attribute &attrib = attributeStack[i];
2010 XmlStringRef prefix(symPrefix(attrib.key));
2011 XmlStringRef key(symString(attrib.key));
2012 XmlStringRef value(symString(attrib.value));
2014 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2015 documentEncoding = value;
2018 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2019 if (!QXmlUtils::isEncName(value))
2020 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2022 QByteArray enc = value.toString().toUtf8();
2023 if (!lockEncoding) {
2024 decoder = QStringDecoder(enc.constData());
2025 if (!decoder.isValid()) {
2029 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2030 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2032 decoder = QStringDecoder(QStringDecoder::Utf8);
2033 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2039 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2040 if (!decoder.hasError())
2041 readBuffer = std::move(buf);
2045 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2046 hasStandalone =
true;
2047 if (value ==
"yes"_L1)
2049 else if (value ==
"no"_L1)
2052 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2054 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2059 raiseWellFormedError(err);
2060 attributeStack.clear();
2064void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2066 this->error = error;
2067 errorString = message;
2068 if (errorString.isNull()) {
2069 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2070 errorString = QXmlStream::tr(
"Premature end of document.");
2071 else if (error == QXmlStreamReader::CustomError)
2072 errorString = QXmlStream::tr(
"Invalid document.");
2075 type = QXmlStreamReader::Invalid;
2078void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2080 raiseError(QXmlStreamReader::NotWellFormedError, message);
2083void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2086 raiseError(QXmlStreamReader::NotWellFormedError,
2087 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2091void QXmlStreamReaderPrivate::parseError()
2094 if (token == EOF_SYMBOL) {
2095 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2099 QString error_message;
2100 int ers = state_stack[tos];
2103 if (token != XML_ERROR)
2104 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2105 int k = t_action(ers, tk);
2109 if (nexpected < nmax)
2110 expected[nexpected++] = tk;
2114 if (nexpected && nexpected < nmax) {
2116 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2117 .arg(QLatin1StringView(spell[expected[0]]));
2118 if (nexpected == 2) {
2120 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2121 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2122 }
else if (nexpected > 2) {
2124 for (; s < nexpected - 1; ++s) {
2126 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2127 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2130 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2131 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2133 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2134 .arg(exp_str, QLatin1StringView(spell[token]));
2136 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2139 raiseWellFormedError(error_message);
2142void QXmlStreamReaderPrivate::resume(
int rule) {
2143 resumeReduction = rule;
2144 if (error == QXmlStreamReader::NoError)
2145 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2149
2150
2151
2152qint64 QXmlStreamReader::lineNumber()
const
2154 Q_D(
const QXmlStreamReader);
2155 return d->lineNumber + 1;
2159
2160
2161
2162qint64 QXmlStreamReader::columnNumber()
const
2164 Q_D(
const QXmlStreamReader);
2165 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2169
2170
2171
2172qint64 QXmlStreamReader::characterOffset()
const
2174 Q_D(
const QXmlStreamReader);
2175 return d->characterOffset + d->readBufferPos;
2180
2181
2182QStringView QXmlStreamReader::text()
const
2184 Q_D(
const QXmlStreamReader);
2190
2191
2192
2193
2194
2195QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2197 Q_D(
const QXmlStreamReader);
2198 if (d->notationDeclarations.size())
2199 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2200 return d->publicNotationDeclarations;
2205
2206
2207
2208
2209
2210QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2212 Q_D(
const QXmlStreamReader);
2213 if (d->entityDeclarations.size())
2214 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2215 return d->publicEntityDeclarations;
2219
2220
2221
2222
2223
2224
2225QStringView QXmlStreamReader::dtdName()
const
2227 Q_D(
const QXmlStreamReader);
2228 if (d->type == QXmlStreamReader::DTD)
2230 return QStringView();
2234
2235
2236
2237
2238
2239
2240QStringView QXmlStreamReader::dtdPublicId()
const
2242 Q_D(
const QXmlStreamReader);
2243 if (d->type == QXmlStreamReader::DTD)
2244 return d->dtdPublicId;
2245 return QStringView();
2249
2250
2251
2252
2253
2254
2255QStringView QXmlStreamReader::dtdSystemId()
const
2257 Q_D(
const QXmlStreamReader);
2258 if (d->type == QXmlStreamReader::DTD)
2259 return d->dtdSystemId;
2260 return QStringView();
2264
2265
2266
2267
2268
2269
2270
2271
2272int QXmlStreamReader::entityExpansionLimit()
const
2274 Q_D(
const QXmlStreamReader);
2275 return d->entityExpansionLimit;
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2295 Q_D(QXmlStreamReader);
2296 d->entityExpansionLimit = limit;
2300
2301
2302
2303
2304
2305
2306
2307
2308QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2310 Q_D(
const QXmlStreamReader);
2311 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2312 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2313 return d->publicNamespaceDeclarations;
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2329 Q_D(QXmlStreamReader);
2330 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2331 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2332 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2336
2337
2338
2339
2340
2341
2342void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2344 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2345 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2368 Q_D(QXmlStreamReader);
2369 if (isStartElement()) {
2372 switch (readNext()) {
2374 case EntityReference:
2375 result.insert(result.size(), d->text);
2379 case ProcessingInstruction:
2383 if (behaviour == SkipChildElements) {
2384 skipCurrentElement();
2386 }
else if (behaviour == IncludeChildElements) {
2387 result += readElementText(behaviour);
2392 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2394 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2404
2405
2406
2407void QXmlStreamReader::raiseError(
const QString& message)
2409 Q_D(QXmlStreamReader);
2410 d->raiseError(CustomError, message);
2414
2415
2416
2417
2418QString QXmlStreamReader::errorString()
const
2420 Q_D(
const QXmlStreamReader);
2421 if (d->type == QXmlStreamReader::Invalid)
2422 return d->errorString;
2427
2428
2429
2430QXmlStreamReader::Error QXmlStreamReader::error()
const
2432 Q_D(
const QXmlStreamReader);
2433 if (d->type == QXmlStreamReader::Invalid)
2439
2440
2441QStringView QXmlStreamReader::processingInstructionTarget()
const
2443 Q_D(
const QXmlStreamReader);
2444 return d->processingInstructionTarget;
2448
2449
2450QStringView QXmlStreamReader::processingInstructionData()
const
2452 Q_D(
const QXmlStreamReader);
2453 return d->processingInstructionData;
2459
2460
2461
2462
2463QStringView QXmlStreamReader::name()
const
2465 Q_D(
const QXmlStreamReader);
2470
2471
2472
2473
2474QStringView QXmlStreamReader::namespaceUri()
const
2476 Q_D(
const QXmlStreamReader);
2477 return d->namespaceUri;
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492QStringView QXmlStreamReader::qualifiedName()
const
2494 Q_D(
const QXmlStreamReader);
2495 return d->qualifiedName;
2501
2502
2503
2504
2505
2506
2507QStringView QXmlStreamReader::prefix()
const
2509 Q_D(
const QXmlStreamReader);
2514
2515
2516QXmlStreamAttributes QXmlStreamReader::attributes()
const
2518 Q_D(
const QXmlStreamReader);
2519 return d->attributes;
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2542
2543
2544QXmlStreamAttribute::QXmlStreamAttribute()
2546 m_isDefault =
false;
2550
2551
2552QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2554 m_namespaceUri = namespaceUri;
2555 m_name = m_qualifiedName = name;
2557 m_namespaceUri = namespaceUri;
2561
2562
2563QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2565 qsizetype colon = qualifiedName.indexOf(u':');
2566 m_name = qualifiedName.mid(colon + 1);
2567 m_qualifiedName = qualifiedName;
2572
2573
2574
2575
2577
2578
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2591
2592
2593
2594
2595
2596
2597
2600
2601
2604
2605
2606
2607
2608
2610
2611
2612
2613
2615
2616
2617
2618
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2643
2644
2645
2646
2649
2650
2651
2652
2653
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2671
2672
2673QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2678
2679
2680
2682
2683
2684
2686
2687
2688
2691
2692
2693
2694
2696
2697
2698
2699
2702
2703
2704
2705
2706
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2722
2723
2724
2725
2727
2728
2729
2730
2733
2734
2735QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2740
2741
2742
2743
2744QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2747 m_namespaceUri = namespaceUri;
2751
2752
2753
2755
2756
2757
2763
2764
2765
2766
2767
2770
2771
2772
2773
2774
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2791
2792
2793QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2798
2799
2800
2802
2803
2804
2806
2807
2808
2810
2811
2812
2814
2815
2816
2819
2820
2821
2822
2824
2825
2826
2827
2830
2831
2832
2833
2834
2835
2836QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2838 for (
const QXmlStreamAttribute &attribute : *
this) {
2839 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2840 return attribute.value();
2842 return QStringView();
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2863 for (
const QXmlStreamAttribute &attribute : *
this) {
2864 if (attribute.qualifiedName() == qualifiedName)
2865 return attribute.value();
2867 return QStringView();
2871
2872
2873
2874void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2876 append(QXmlStreamAttribute(namespaceUri, name, value));
2880
2881
2882
2883void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
2885 append(QXmlStreamAttribute(qualifiedName, value));
2888#if QT_CONFIG(xmlstreamreader)
2891
2892
2894
2895
2897
2898
2900
2901
2903
2904
2905
2906
2908
2909
2911
2912
2914
2915
2917
2918
2921
2922
2923
2924
2925bool QXmlStreamReader::isWhitespace()
const
2927 Q_D(
const QXmlStreamReader);
2928 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
2932
2933
2934
2935
2936bool QXmlStreamReader::isCDATA()
const
2938 Q_D(
const QXmlStreamReader);
2939 return d->type == QXmlStreamReader::Characters && d->isCDATA;
2945
2946
2947
2948
2949
2950
2951
2952bool QXmlStreamReader::isStandaloneDocument()
const
2954 Q_D(
const QXmlStreamReader);
2955 return d->standalone;
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968bool QXmlStreamReader::hasStandaloneDeclaration()
const
2970 Q_D(
const QXmlStreamReader);
2971 return d->hasStandalone;
2975
2976
2977
2978
2979
2980
2981QStringView QXmlStreamReader::documentVersion()
const
2983 Q_D(
const QXmlStreamReader);
2984 if (d->type == QXmlStreamReader::StartDocument)
2985 return d->documentVersion;
2986 return QStringView();
2990
2991
2992
2993
2994
2995
2996QStringView QXmlStreamReader::documentEncoding()
const
2998 Q_D(
const QXmlStreamReader);
2999 if (d->type == QXmlStreamReader::StartDocument)
3000 return d->documentEncoding;
3001 return QStringView();
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3122#if QT_CONFIG(xmlstreamwriter)
3124class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3126 QXmlStreamWriter *q_ptr;
3127 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3129 enum class StartElementOption {
3131 OmitNamespaceDeclarations = 1,
3134 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3135 ~QXmlStreamWriterPrivate() {
3140 void raiseError(QXmlStreamWriter::Error error);
3141 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3142 void write(QAnyStringView s);
3143 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3144 bool finishStartElement(
bool contents =
true);
3145 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3146 StartElementOption option = StartElementOption::KeepEverything);
3147 QIODevice *device =
nullptr;
3148 QString *stringDevice =
nullptr;
3149 uint deleteDevice :1;
3150 uint inStartElement :1;
3151 uint inEmptyElement :1;
3152 uint lastWasStartElement :1;
3153 uint wroteSomething :1;
3154 uint autoFormatting :1;
3155 uint didWriteStartDocument :1;
3156 uint didWriteAnyToken :1;
3157 uint stopWritingOnError :1;
3158 std::string autoFormattingIndent = std::string(4,
' ');
3159 NamespaceDeclaration emptyNamespace;
3160 qsizetype lastNamespaceDeclaration = 1;
3161 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3162 QString errorString;
3164 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3165 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3166 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3168 int namespacePrefixCount = 0;
3170 void indent(
int level);
3172 void doWriteToDevice(QStringView s);
3173 void doWriteToDevice(QUtf8StringView s);
3174 void doWriteToDevice(QLatin1StringView s);
3178QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3179 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3180 inEmptyElement(
false), lastWasStartElement(
false),
3181 wroteSomething(
false), autoFormatting(
false),
3182 didWriteStartDocument(
false), didWriteAnyToken(
false),
3183 stopWritingOnError(
false)
3187void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3191 case QXmlStreamWriter::Error::IO:
3192 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3194 case QXmlStreamWriter::Error::Encoding:
3195 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3197 case QXmlStreamWriter::Error::InvalidCharacter:
3198 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3200 case QXmlStreamWriter::Error::Custom:
3201 errorString = QXmlStream::tr(
"An error occurred while writing");
3203 case QXmlStreamWriter::Error::None:
3204 errorString.clear();
3209void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3212 errorString = message.toString();
3215void QXmlStreamWriterPrivate::write(QAnyStringView s)
3217 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3220 if (error == QXmlStreamWriter::Error::IO)
3223 s.visit([&] (
auto s) { doWriteToDevice(s); });
3224 }
else if (stringDevice) {
3225 s.visit([&] (
auto s) { stringDevice->append(s); });
3227 qWarning(
"QXmlStreamWriter: No device");
3231void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3238 NextResult operator()(
const char *&it,
const char *)
const
3239 {
return {uchar(*it++),
false}; }
3242 NextResult operator()(
const char *&it,
const char *end)
const
3246 constexpr char32_t invalidValue = 0xFFFFFFFF;
3247 static_assert(invalidValue > QChar::LastValidCodePoint);
3248 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3249 const auto old_i = i;
3250 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3251 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3253 return result == invalidValue ? NextResult{U'\0',
true}
3254 : NextResult{result,
false};
3258 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3260 QStringIterator decoder(it, end);
3263 constexpr char32_t invalidValue = 0xFFFFFFFF;
3264 static_assert(invalidValue > QChar::LastValidCodePoint);
3265 char32_t result = decoder.next(invalidValue);
3266 it = decoder.position();
3267 return result == invalidValue ? NextResult{U'\0',
true}
3268 : NextResult{result,
false};
3273 escaped.reserve(s.size());
3274 s.visit([&] (
auto s) {
3275 using View =
decltype(s);
3276 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3277 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3279 auto it = s.begin();
3280 const auto end = s.end();
3284 QLatin1StringView replacement;
3289 const auto decoded = decoder(next_it, end);
3290 switch (decoded.value) {
3292 replacement =
"<"_L1;
3295 replacement =
">"_L1;
3298 replacement =
"&"_L1;
3301 replacement =
"""_L1;
3304 if (escapeWhitespace)
3305 replacement =
"	"_L1;
3308 if (escapeWhitespace)
3309 replacement =
" "_L1;
3312 if (escapeWhitespace)
3313 replacement =
" "_L1;
3317 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3318 if (stopWritingOnError)
3320 replacement =
""_L1;
3321 Q_ASSERT(!replacement.isNull());
3324 if (decoded.value > 0x1F)
3330 raiseError(decoded.encodingError
3331 ? QXmlStreamWriter::Error::Encoding
3332 : QXmlStreamWriter::Error::InvalidCharacter);
3333 if (stopWritingOnError)
3335 replacement =
""_L1;
3336 Q_ASSERT(!replacement.isNull());
3339 if (!replacement.isNull())
3344 escaped.append(View{mark, it});
3345 escaped.append(replacement);
3354void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3355 if (namespaceDeclaration.prefix.isEmpty()) {
3357 write(namespaceDeclaration.namespaceUri);
3361 write(namespaceDeclaration.prefix);
3363 write(namespaceDeclaration.namespaceUri);
3366 didWriteAnyToken =
true;
3369bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3371 bool hadSomethingWritten = wroteSomething;
3372 wroteSomething = contents;
3373 if (!inStartElement)
3374 return hadSomethingWritten;
3376 if (inEmptyElement) {
3378 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3379 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3380 lastWasStartElement =
false;
3384 inStartElement = inEmptyElement =
false;
3385 lastNamespaceDeclaration = namespaceDeclarations.size();
3386 didWriteAnyToken =
true;
3387 return hadSomethingWritten;
3390QXmlStreamPrivateTagStack::NamespaceDeclaration &
3391QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3393 const bool prefixIsXml = prefix ==
"xml"_L1;
3394 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3395 if (prefixIsXml && !namespaceUriIsXml) {
3396 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3397 "than 'http://www.w3.org/XML/1998/namespace'");
3398 }
else if (!prefixIsXml && namespaceUriIsXml) {
3399 const QString prefixString = prefix.toString();
3400 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3401 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3402 qUtf16Printable(prefixString));
3404 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3405 const QString prefixString = prefix.toString();
3406 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3407 "'http://www.w3.org/2000/xmlns/'",
3408 qUtf16Printable(prefixString));
3410 auto &namespaceDeclaration = namespaceDeclarations.push();
3411 namespaceDeclaration.prefix = addToStringStorage(prefix);
3412 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3413 return namespaceDeclaration;
3416QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3418 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3419 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3420 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3421 return namespaceDeclaration;
3424 if (namespaceUri.isEmpty())
3425 return emptyNamespace;
3426 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3427 if (namespaceUri.isEmpty()) {
3428 namespaceDeclaration.prefix.clear();
3431 int n = ++namespacePrefixCount;
3433 s = u'n' + QString::number(n++);
3434 qsizetype j = namespaceDeclarations.size() - 2;
3435 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3440 namespaceDeclaration.prefix = addToStringStorage(s);
3442 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3443 if (writeDeclaration)
3444 writeNamespaceDeclaration(namespaceDeclaration);
3445 return namespaceDeclaration;
3450void QXmlStreamWriterPrivate::indent(
int level)
3452 if (didWriteStartDocument || didWriteAnyToken)
3454 for (
int i = 0; i < level; ++i)
3455 write(autoFormattingIndent);
3458void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3460 constexpr qsizetype MaxChunkSize = 512;
3461 char buffer [3 * MaxChunkSize];
3462 QStringEncoder::State state;
3463 while (!s.isEmpty()) {
3464 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3465 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3466 doWriteToDevice(QUtf8StringView{buffer, end});
3467 s = s.sliced(chunkSize);
3469 if (state.remainingChars > 0)
3470 raiseError(QXmlStreamWriter::Error::Encoding);
3473void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3475 QByteArrayView bytes = s;
3476 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3477 raiseError(QXmlStreamWriter::Error::IO);
3480void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3482 constexpr qsizetype MaxChunkSize = 512;
3483 char buffer [2 * MaxChunkSize];
3484 while (!s.isEmpty()) {
3485 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3486 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3487 doWriteToDevice(QUtf8StringView{buffer, end});
3488 s = s.sliced(chunkSize);
3493
3494
3495
3496
3497QXmlStreamWriter::QXmlStreamWriter()
3498 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3503
3504
3505QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3506 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3508 Q_D(QXmlStreamWriter);
3513
3514
3515
3516QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3517 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3519 Q_D(QXmlStreamWriter);
3520 d->device =
new QBuffer(array);
3521 d->device->open(QIODevice::WriteOnly);
3522 d->deleteDevice =
true;
3527
3528QXmlStreamWriter::QXmlStreamWriter(QString *string)
3529 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3531 Q_D(QXmlStreamWriter);
3532 d->stringDevice = string;
3536
3537
3538QXmlStreamWriter::~QXmlStreamWriter()
3544
3545
3546
3547
3548
3549void QXmlStreamWriter::setDevice(QIODevice *device)
3551 Q_D(QXmlStreamWriter);
3552 if (device == d->device)
3554 d->stringDevice =
nullptr;
3555 if (d->deleteDevice) {
3557 d->deleteDevice =
false;
3563
3564
3565
3566
3567
3568QIODevice *QXmlStreamWriter::device()
const
3570 Q_D(
const QXmlStreamWriter);
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3591
3592
3593
3594
3595
3596
3597
3598void QXmlStreamWriter::setAutoFormatting(
bool enable)
3600 Q_D(QXmlStreamWriter);
3601 d->autoFormatting = enable;
3605
3606
3607
3608
3609bool QXmlStreamWriter::autoFormatting()
const
3611 Q_D(
const QXmlStreamWriter);
3612 return d->autoFormatting;
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3629void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3631 Q_D(QXmlStreamWriter);
3632 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3635int QXmlStreamWriter::autoFormattingIndent()
const
3637 Q_D(
const QXmlStreamWriter);
3638 const QLatin1StringView indent(d->autoFormattingIndent);
3639 return indent.count(u' ') - indent.count(u'\t');
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659bool QXmlStreamWriter::stopWritingOnError()
const
3661 Q_D(
const QXmlStreamWriter);
3662 return d->stopWritingOnError;
3665void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3667 Q_D(QXmlStreamWriter);
3668 d->stopWritingOnError = stop;
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683bool QXmlStreamWriter::hasError()
const
3685 return error() != QXmlStreamWriter::Error::None;
3689
3690
3691
3692
3693
3694
3695
3696
3697QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3699 Q_D(
const QXmlStreamWriter);
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713QString QXmlStreamWriter::errorString()
const
3715 Q_D(
const QXmlStreamWriter);
3716 return d->errorString;
3720
3721
3722
3723
3724
3725
3726
3727
3728void QXmlStreamWriter::raiseError(QAnyStringView message)
3730 Q_D(QXmlStreamWriter);
3731 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3747 Q_D(QXmlStreamWriter);
3748 Q_ASSERT(d->inStartElement);
3749 Q_ASSERT(count(qualifiedName,
':') <= 1);
3751 d->write(qualifiedName);
3753 d->writeEscaped(value,
true);
3755 d->didWriteAnyToken =
true;
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3771 Q_D(QXmlStreamWriter);
3772 Q_ASSERT(d->inStartElement);
3773 Q_ASSERT(!contains(name,
':'));
3774 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3776 if (!namespaceDeclaration.prefix.isEmpty()) {
3777 d->write(namespaceDeclaration.prefix);
3782 d->writeEscaped(value,
true);
3784 d->didWriteAnyToken =
true;
3788
3789
3790
3791
3792
3793
3794
3795void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3797 if (attribute.namespaceUri().isEmpty())
3798 writeAttribute(attribute.qualifiedName(), attribute.value());
3800 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3805
3806
3807
3808
3809
3810
3811
3812
3813void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3815 Q_D(QXmlStreamWriter);
3816 Q_ASSERT(d->inStartElement);
3818 for (
const auto &attr : attributes)
3819 writeAttribute(attr);
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3836 Q_D(QXmlStreamWriter);
3837 d->finishStartElement();
3838 d->write(
"<![CDATA[");
3839 while (!text.isEmpty()) {
3840 const auto idx = indexOf(text,
"]]>"_L1);
3843 d->write(text.first(idx));
3847 text = text.sliced(idx + 3);
3855
3856
3857
3858
3859
3860
3861
3862
3863void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3865 Q_D(QXmlStreamWriter);
3866 d->finishStartElement();
3867 d->writeEscaped(text);
3872
3873
3874
3875
3876
3877
3878void QXmlStreamWriter::writeComment(QAnyStringView text)
3880 Q_D(QXmlStreamWriter);
3881 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
3882 if (!d->finishStartElement(
false) && d->autoFormatting)
3883 d->indent(d->tagStack.size());
3887 d->inStartElement = d->lastWasStartElement =
false;
3892
3893
3894
3895
3896
3897void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
3899 Q_D(QXmlStreamWriter);
3900 d->finishStartElement();
3901 if (d->autoFormatting)
3904 if (d->autoFormatting)
3911
3912
3913
3914
3915
3916
3917void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
3919 Q_D(QXmlStreamWriter);
3920 Q_ASSERT(count(qualifiedName,
':') <= 1);
3921 d->writeStartElement({}, qualifiedName);
3922 d->inEmptyElement =
true;
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
3938 Q_D(QXmlStreamWriter);
3939 Q_ASSERT(!contains(name,
':'));
3940 d->writeStartElement(namespaceUri, name);
3941 d->inEmptyElement =
true;
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
3957 writeStartElement(qualifiedName);
3958 writeCharacters(text);
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
3976 writeStartElement(namespaceUri, name);
3977 writeCharacters(text);
3983
3984
3985
3986
3987void QXmlStreamWriter::writeEndDocument()
3989 Q_D(QXmlStreamWriter);
3990 while (d->tagStack.size())
3992 if (d->didWriteStartDocument || d->didWriteAnyToken)
3997
3998
3999
4000
4001void QXmlStreamWriter::writeEndElement()
4003 Q_D(QXmlStreamWriter);
4004 Q_ASSERT(d->didWriteAnyToken);
4005 if (d->tagStack.isEmpty())
4009 if (d->inStartElement && !d->inEmptyElement) {
4011 d->lastWasStartElement = d->inStartElement =
false;
4012 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4013 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4017 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4018 d->indent(d->tagStack.size()-1);
4019 if (d->tagStack.isEmpty())
4021 d->lastWasStartElement =
false;
4022 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4023 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4025 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4026 d->write(tag.namespaceDeclaration.prefix);
4036
4037
4038
4039
4040
4041void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4043 Q_D(QXmlStreamWriter);
4044 d->finishStartElement();
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4070 Q_D(QXmlStreamWriter);
4071 Q_ASSERT(prefix !=
"xmlns"_L1);
4072 if (prefix.isEmpty()) {
4073 d->findNamespace(namespaceUri, d->inStartElement);
4075 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4076 if (d->inStartElement)
4077 d->writeNamespaceDeclaration(namespaceDeclaration);
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4097 Q_D(QXmlStreamWriter);
4098 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4099 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4100 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4101 namespaceDeclaration.prefix.clear();
4102 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4103 if (d->inStartElement)
4104 d->writeNamespaceDeclaration(namespaceDeclaration);
4109
4110
4111
4112
4113
4114
4115void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4117 Q_D(QXmlStreamWriter);
4118 Q_ASSERT(!contains(data,
"?>"_L1));
4119 if (!d->finishStartElement(
false) && d->autoFormatting)
4120 d->indent(d->tagStack.size());
4123 if (!data.isNull()) {
4128 d->didWriteAnyToken =
true;
4134
4135
4136
4137
4138
4139
4140void QXmlStreamWriter::writeStartDocument()
4142 writeStartDocument(
"1.0"_L1);
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4164 Q_D(QXmlStreamWriter);
4165 d->finishStartElement(
false);
4166 d->write(
"<?xml version=\"");
4169 d->write(
"\" encoding=\"UTF-8");
4171 d->didWriteStartDocument =
true;
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4194 Q_D(QXmlStreamWriter);
4195 d->finishStartElement(
false);
4196 d->write(
"<?xml version=\"");
4199 d->write(
"\" encoding=\"UTF-8");
4201 d->write(
"\" standalone=\"yes\"?>");
4203 d->write(
"\" standalone=\"no\"?>");
4204 d->didWriteStartDocument =
true;
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4220 Q_D(QXmlStreamWriter);
4221 Q_ASSERT(count(qualifiedName,
':') <= 1);
4222 d->writeStartElement({}, qualifiedName);
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4239 Q_D(QXmlStreamWriter);
4240 Q_ASSERT(!contains(name,
':'));
4241 d->writeStartElement(namespaceUri, name);
4244void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4245 StartElementOption option)
4247 if (!finishStartElement(
false) && autoFormatting)
4248 indent(tagStack.size());
4250 Tag &tag = tagStack_push();
4251 tag.name = addToStringStorage(name);
4252 tag.namespaceDeclaration = findNamespace(namespaceUri);
4254 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4255 write(tag.namespaceDeclaration.prefix);
4259 inStartElement = lastWasStartElement =
true;
4261 if (option != StartElementOption::OmitNamespaceDeclarations) {
4262 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4263 writeNamespaceDeclaration(namespaceDeclarations[i]);
4265 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4266 didWriteAnyToken =
true;
4269#if QT_CONFIG(xmlstreamreader)
4271
4272
4273
4274
4275
4276
4277void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4279 Q_D(QXmlStreamWriter);
4280 switch (reader.tokenType()) {
4281 case QXmlStreamReader::NoToken:
4283 case QXmlStreamReader::StartDocument:
4284 writeStartDocument();
4286 case QXmlStreamReader::EndDocument:
4289 case QXmlStreamReader::StartElement: {
4291 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4292 for (
const auto &namespaceDeclaration : reader.namespaceDeclarations()) {
4293 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4294 namespaceDeclaration.prefix());
4295 extraNamespaces.append(extraNamespace);
4297 d->writeStartElement(
4298 reader.namespaceUri(), reader.name(),
4299 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4301 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4302 d->writeNamespaceDeclaration(extraNamespace);
4303 writeAttributes(reader.attributes());
4305 case QXmlStreamReader::EndElement:
4308 case QXmlStreamReader::Characters:
4309 if (reader.isCDATA())
4310 writeCDATA(reader.text());
4312 writeCharacters(reader.text());
4314 case QXmlStreamReader::Comment:
4315 writeComment(reader.text());
4317 case QXmlStreamReader::DTD:
4318 writeDTD(reader.text());
4320 case QXmlStreamReader::EntityReference:
4321 writeEntityReference(reader.name());
4323 case QXmlStreamReader::ProcessingInstruction:
4324 writeProcessingInstruction(reader.processingInstructionTarget(),
4325 reader.processingInstructionData());
4328 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4329 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4336#if QT_CONFIG(xmlstreamreader)
4337static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4338 QXmlStreamReaderPrivate::XmlContext ctxt)
4341 case QXmlStreamReader::StartDocument:
4342 case QXmlStreamReader::DTD:
4343 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4345 case QXmlStreamReader::StartElement:
4346 case QXmlStreamReader::EndElement:
4347 case QXmlStreamReader::Characters:
4348 case QXmlStreamReader::EntityReference:
4349 case QXmlStreamReader::EndDocument:
4350 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4352 case QXmlStreamReader::Comment:
4353 case QXmlStreamReader::ProcessingInstruction:
4356 case QXmlStreamReader::NoToken:
4357 case QXmlStreamReader::Invalid:
4362#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4363 Q_UNREACHABLE_RETURN(
false);
4370
4371
4372
4373
4374
4375
4376bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4379 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4383 const bool result = isTokenAllowedInContext(type, currentContext);
4384 if (result || currentContext == XmlContext::Body)
4388 currentContext = XmlContext::Body;
4389 return isTokenAllowedInContext(type, currentContext);
4393
4394
4395
4396
4397void QXmlStreamReaderPrivate::checkToken()
4399 Q_Q(QXmlStreamReader);
4402 const XmlContext context = currentContext;
4403 const bool ok = isValidToken(type);
4406 if (error != QXmlStreamReader::Error::NoError)
4410 raiseError(QXmlStreamReader::UnexpectedElementError,
4411 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4412 .arg(q->tokenString(), contextString(context)));
4416 if (type != QXmlStreamReader::DTD)
4421 raiseError(QXmlStreamReader::UnexpectedElementError,
4422 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4443
4444
4445
4446
4447
4448
4449
4450