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 tagStackStringStorageSize = 0;
969 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
970 namespaceDeclaration.namespaceUri = addToStringStorage(u"http://www.w3.org/XML/1998/namespace");
971 namespaceDeclaration.prefix = addToStringStorage(u"xml");
972 initialTagStackStringStorageSize = tagStackStringStorageSize;
976#if QT_CONFIG(xmlstreamreader)
978QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
982 deleteDevice =
false;
985 state_stack =
nullptr;
987 entityResolver =
nullptr;
989#define ADD_PREDEFINED(n, v)
991 Entity e = Entity::createLiteral(n##_L1, v##_L1);
992 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e));
994 ADD_PREDEFINED(
"lt",
"<");
995 ADD_PREDEFINED(
"gt",
">");
996 ADD_PREDEFINED(
"amp",
"&");
997 ADD_PREDEFINED(
"apos",
"'");
998 ADD_PREDEFINED(
"quot",
"\"");
1002void QXmlStreamReaderPrivate::init()
1005 lastAttributeIsCData =
false;
1008 isEmptyElement =
false;
1009 isWhitespace =
true;
1012 hasStandalone =
false;
1014 resumeReduction = 0;
1015 state_stack[tos++] = 0;
1016 state_stack[tos] = 0;
1018 putStack.reserve(32);
1020 textBuffer.reserve(256);
1024 attributes.reserve(16);
1025 lineNumber = lastLineStart = characterOffset = 0;
1028 decoder = QStringDecoder();
1029 attributeStack.clear();
1030 attributeStack.reserve(16);
1031 entityParser.reset();
1032 hasCheckedStartDocument =
false;
1033 normalizeLiterals =
false;
1036 inParseEntity =
false;
1037 referenceToUnparsedEntityDetected =
false;
1038 referenceToParameterEntityDetected =
false;
1039 hasExternalDtdSubset =
false;
1040 lockEncoding =
false;
1041 namespaceProcessing =
true;
1042 rawReadBuffer.clear();
1043 chunkDecoder = QStringDecoder();
1046 tagStackStringStorageSize = initialTagStackStringStorageSize;
1048 type = QXmlStreamReader::NoToken;
1049 error = QXmlStreamReader::NoError;
1050 currentContext = XmlContext::Prolog;
1055
1056
1057
1058void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1060 Q_Q(QXmlStreamReader);
1062 if (value.isEmpty())
1067 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1069 entityParser->init();
1070 entityParser->inParseEntity =
true;
1071 entityParser->readBuffer = value;
1072 entityParser->injectToken(PARSE_ENTITY);
1073 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1074 entityParser->parse();
1075 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1076 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1080inline void QXmlStreamReaderPrivate::reallocateStack()
1083 void *p = realloc(sym_stack, stack_size *
sizeof(Value));
1085 sym_stack =
static_cast<Value*>(p);
1086 p = realloc(state_stack, stack_size *
sizeof(
int));
1088 state_stack =
static_cast<
int*>(p);
1092QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1099inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1101 uint peekc = peekChar();
1102 if (peekc ==
'\n') {
1103 if (putStack.size())
1109 if (peekc == StreamEOF) {
1117
1118
1119
1120inline uint QXmlStreamReaderPrivate::getChar()
1123 if (putStack.size()) {
1124 c = atEnd ? StreamEOF : putStack.pop();
1126 if (readBufferPos < readBuffer.size())
1127 c = readBuffer.at(readBufferPos++).unicode();
1129 c = getChar_helper();
1135inline uint QXmlStreamReaderPrivate::peekChar()
1138 if (putStack.size()) {
1140 }
else if (readBufferPos < readBuffer.size()) {
1141 c = readBuffer.at(readBufferPos).unicode();
1143 if ((c = getChar_helper()) != StreamEOF)
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1164 const qsizetype pos = textBuffer.size();
1165 const auto oldLineNumber = lineNumber;
1168 while ((c = getChar()) != StreamEOF) {
1172 if ((c = filterCarriageReturn()) == 0)
1177 lastLineStart = characterOffset + readBufferPos;
1180 textBuffer += QChar(c);
1183 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1184 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1185 lineNumber = oldLineNumber;
1188 textBuffer += QChar(c);
1193 if (c == uint(*str)) {
1195 if (tokenToInject >= 0)
1196 injectToken(tokenToInject);
1199 if (scanString(str + 1, tokenToInject,
false))
1204 putString(textBuffer, pos);
1205 textBuffer.resize(pos);
1206 lineNumber = oldLineNumber;
1210bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1215 if (c != ushort(str[n])) {
1219 putChar(ushort(str[n]));
1225 textBuffer += QLatin1StringView(str, n);
1227 const qsizetype s = fastScanSpace();
1229 qsizetype pos = textBuffer.size() - n - s;
1230 putString(textBuffer, pos);
1231 textBuffer.resize(pos);
1235 if (tokenToInject >= 0)
1236 injectToken(tokenToInject);
1240bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1242 switch (peekChar()) {
1244 return scanString(spell[CDATA_START], CDATA_START,
false);
1246 return scanString(spell[DOCTYPE], DOCTYPE);
1248 return scanString(spell[ATTLIST], ATTLIST);
1250 return scanString(spell[NOTATION], NOTATION);
1252 if (scanString(spell[ELEMENT], ELEMENT))
1254 return scanString(spell[ENTITY], ENTITY);
1262bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1264 switch (peekChar()) {
1266 return scanString(spell[SYSTEM], SYSTEM);
1268 return scanString(spell[PUBLIC], PUBLIC);
1275bool QXmlStreamReaderPrivate::scanNData()
1277 if (fastScanSpace()) {
1278 if (scanString(spell[NDATA], NDATA))
1285bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1287 switch (peekChar()) {
1289 return scanString(spell[REQUIRED], REQUIRED,
false);
1291 return scanString(spell[IMPLIED], IMPLIED,
false);
1293 return scanString(spell[FIXED], FIXED,
false);
1300bool QXmlStreamReaderPrivate::scanAttType()
1302 switch (peekChar()) {
1304 return scanString(spell[CDATA], CDATA);
1306 if (scanString(spell[ID], ID))
1308 if (scanString(spell[IDREF], IDREF))
1310 return scanString(spell[IDREFS], IDREFS);
1312 if (scanString(spell[ENTITY], ENTITY))
1314 return scanString(spell[ENTITIES], ENTITIES);
1316 if (scanString(spell[NOTATION], NOTATION))
1318 if (scanString(spell[NMTOKEN], NMTOKEN))
1320 return scanString(spell[NMTOKENS], NMTOKENS);
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1343 while ((c = getChar()) != StreamEOF) {
1344 switch (ushort(c)) {
1349
1353 if (filterCarriageReturn() == 0)
1358 lastLineStart = characterOffset + readBufferPos;
1362 if (normalizeLiterals)
1365 textBuffer += QChar(c);
1372 if (!(c & 0xff0000)) {
1382 textBuffer += QChar(ushort(c));
1389inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1393 while ((c = getChar()) != StreamEOF) {
1396 if ((c = filterCarriageReturn()) == 0)
1401 lastLineStart = characterOffset + readBufferPos;
1405 textBuffer += QChar(c);
1417
1418
1419
1420
1421
1422inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1426 while ((c = getChar()) != StreamEOF) {
1427 switch (ushort(c)) {
1434 isWhitespace =
false;
1435 const qsizetype pos = textBuffer.size();
1436 textBuffer += QChar(ushort(c));
1438 while ((c = getChar()) ==
']') {
1439 textBuffer += QChar(ushort(c));
1442 if (c == StreamEOF) {
1443 putString(textBuffer, pos);
1444 textBuffer.resize(pos);
1445 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1446 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1454 if ((c = filterCarriageReturn()) == 0)
1459 lastLineStart = characterOffset + readBufferPos;
1463 textBuffer += QChar(ushort(c));
1468 if (!(c & 0xff0000)) {
1478 isWhitespace =
false;
1479 textBuffer += QChar(ushort(c));
1487inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1491 while ((c = getChar()) != StreamEOF) {
1495 raiseNamePrefixTooLongError();
1496 return std::nullopt;
1525 if (val && val->prefix == n + 1) {
1533 if (val->prefix == 0) {
1534 val->prefix = qint16(n + 2);
1545 textBuffer += QChar(ushort(c));
1552 qsizetype pos = textBuffer.size() - n;
1553 putString(textBuffer, pos);
1554 textBuffer.resize(pos);
1558enum NameChar { NameBeginning, NameNotBeginning, NotName };
1560static const char Begi =
static_cast<
char>(NameBeginning);
1561static const char NtBg =
static_cast<
char>(NameNotBeginning);
1562static const char NotN =
static_cast<
char>(NotName);
1564static const char nameCharTable[128] =
1567 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1568 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1570 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1571 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1573 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1574 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1576 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1577 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1579 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1580 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1582 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1583 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1585 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1586 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1588 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1589 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1592static inline NameChar fastDetermineNameChar(QChar ch)
1594 ushort uc = ch.unicode();
1596 return static_cast<NameChar>(nameCharTable[uc]);
1598 QChar::Category cat = ch.category();
1600 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1601 || cat == QChar::Number_Letter)
1602 return NameBeginning;
1603 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1604 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1605 return NameNotBeginning;
1609inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1613 while ((c = getChar()) != StreamEOF) {
1614 if (fastDetermineNameChar(QChar(c)) == NotName) {
1619 textBuffer += QChar(c);
1623 qsizetype pos = textBuffer.size() - n;
1624 putString(textBuffer, pos);
1625 textBuffer.resize(pos);
1630void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1633 putString(s.mid(from));
1636 putStack.reserve(s.size());
1637 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1638 putStack.rawPush() = it->unicode();
1641void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1643 putStack.reserve(s.size());
1644 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1645 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1648void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1650 putStack.reserve(s.size());
1651 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1652 char16_t c = it->unicode();
1653 if (c ==
'\n' || c ==
'\r')
1654 putStack.rawPush() = ((LETTER << 16) | c);
1656 putStack.rawPush() = c;
1659void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1661 putStack.reserve(s.size());
1662 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1663 char16_t c = it->unicode();
1664 if (c ==
'&' || c ==
';')
1665 putStack.rawPush() = c;
1666 else if (c ==
'\n' || c ==
'\r')
1667 putStack.rawPush() =
' ';
1669 putStack.rawPush() = ((LETTER << 16) | c);
1673uint QXmlStreamReaderPrivate::getChar_helper()
1675 constexpr qsizetype BUFFER_SIZE = 8192;
1676 characterOffset += readBufferPos;
1678 if (readBuffer.size())
1679 readBuffer.resize(0);
1680 if (decoder.isValid())
1683 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1684 if (!decoder.isValid()) {
1686 if (nbytesread < 4) {
1690 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1692 encoding = QStringDecoder::Utf8;
1693 decoder = QStringDecoder(*encoding);
1696 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1698 if (lockEncoding && decoder.hasError()) {
1707 rawReadBuffer.resize(BUFFER_SIZE);
1708 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1709 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1716 if (!tryDecodeWithGlobalDecoder())
1718 }
else if (dataInfo.empty()) {
1722 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1729 if (bufAndEnc.encoding == QStringDecoder::System) {
1731 rawReadBuffer += bufAndEnc.buffer;
1733 rawReadBuffer = bufAndEnc.buffer;
1734 nbytesread = rawReadBuffer.size();
1736 if (!tryDecodeWithGlobalDecoder()) {
1738 bool hasError =
true;
1739 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1740 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1741 hasError = chunkDecoder.hasError();
1744 raiseWellFormedError(
1745 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1750 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1751 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1752 readBuffer = chunkDecoder(bufAndEnc.buffer);
1756 readBuffer.reserve(1);
1758 if (readBufferPos < readBuffer.size()) {
1759 ushort c = readBuffer.at(readBufferPos++).unicode();
1767XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1769 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1770 if (namespaceDeclaration.prefix == prefix) {
1771 return namespaceDeclaration.namespaceUri;
1776 if (namespaceProcessing && !prefix.isEmpty())
1777 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1780 return XmlStringRef();
1784
1785
1786void QXmlStreamReaderPrivate::resolveTag()
1788 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1789 const qsizetype n = attributeStack.size();
1791 if (namespaceProcessing) {
1792 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1793 if (!dtdAttribute.isNamespaceAttribute
1794 || dtdAttribute.defaultValue.isNull()
1795 || dtdAttribute.tagName != qualifiedName
1796 || dtdAttribute.attributeQualifiedName.isNull())
1799 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1803 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1804 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1805 namespaceDeclaration.prefix.clear();
1807 const XmlStringRef ns(dtdAttribute.defaultValue);
1808 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1809 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1810 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1812 namespaceDeclaration.namespaceUri = ns;
1813 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1814 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1815 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1816 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1817 if (((namespacePrefix ==
"xml"_L1)
1818 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1819 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1820 || namespaceUri.isEmpty()
1821 || namespacePrefix ==
"xmlns"_L1)
1822 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1824 namespaceDeclaration.prefix = namespacePrefix;
1825 namespaceDeclaration.namespaceUri = namespaceUri;
1830 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1832 attributes.resize(n);
1834 for (qsizetype i = 0; i < n; ++i) {
1835 QXmlStreamAttribute &attribute = attributes[i];
1836 Attribute &attrib = attributeStack[i];
1837 XmlStringRef prefix(symPrefix(attrib.key));
1838 XmlStringRef name(symString(attrib.key));
1839 XmlStringRef qualifiedName(symName(attrib.key));
1840 XmlStringRef value(symString(attrib.value));
1842 attribute.m_name = name;
1843 attribute.m_qualifiedName = qualifiedName;
1844 attribute.m_value = value;
1846 if (!prefix.isEmpty()) {
1847 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1848 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1851 for (qsizetype j = 0; j < i; ++j) {
1852 if (attributes[j].name() == attribute.name()
1853 && attributes[j].namespaceUri() == attribute.namespaceUri()
1854 && (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName()))
1856 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1862 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1863 if (dtdAttribute.isNamespaceAttribute
1864 || dtdAttribute.defaultValue.isNull()
1865 || dtdAttribute.tagName != qualifiedName
1866 || dtdAttribute.attributeQualifiedName.isNull())
1869 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1876 QXmlStreamAttribute attribute;
1877 attribute.m_name = dtdAttribute.attributeName;
1878 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1879 attribute.m_value = dtdAttribute.defaultValue;
1881 if (!dtdAttribute.attributePrefix.isEmpty()) {
1882 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1883 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1885 attribute.m_isDefault =
true;
1886 attributes.append(std::move(attribute));
1890void QXmlStreamReaderPrivate::resolvePublicNamespaces()
1892 const Tag &tag = tagStack.top();
1893 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
1894 publicNamespaceDeclarations.resize(n);
1895 for (qsizetype i = 0; i < n; ++i) {
1896 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
1897 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
1898 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
1899 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
1903void QXmlStreamReaderPrivate::resolveDtd()
1905 publicNotationDeclarations.resize(notationDeclarations.size());
1906 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
1907 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
1908 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
1909 publicNotationDeclaration.m_name = notationDeclaration.name;
1910 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
1911 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
1914 notationDeclarations.clear();
1915 publicEntityDeclarations.resize(entityDeclarations.size());
1916 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
1917 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
1918 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
1919 publicEntityDeclaration.m_name = entityDeclaration.name;
1920 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
1921 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
1922 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
1923 publicEntityDeclaration.m_value = entityDeclaration.value;
1925 entityDeclarations.clear();
1926 parameterEntityHash.clear();
1929uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
1934 if (sym(symbolIndex).c ==
'x')
1935 s = symString(symbolIndex).view().sliced(1).toUInt(&ok, 16);
1937 s = symString(symbolIndex).view().toUInt(&ok, 10);
1939 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
1940 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
1946void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
1950 const char16_t *data = publicId.utf16();
1953 for (i = publicId.size() - 1; i >= 0; --i) {
1955 switch ((c = data[i])) {
1956 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
1957 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
1958 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
1959 case '$':
case '_':
case '%':
case '\'':
case '\"':
1962 if (isAsciiLetterOrNumber(c))
1968 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
1972
1973
1974
1975
1976bool QXmlStreamReaderPrivate::checkStartDocument()
1978 hasCheckedStartDocument =
true;
1980 if (scanString(spell[XML], XML))
1983 type = QXmlStreamReader::StartDocument;
1985 hasCheckedStartDocument =
false;
1986 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
1991void QXmlStreamReaderPrivate::startDocument()
1994 if (documentVersion !=
"1.0"_L1) {
1995 if (documentVersion.view().contains(u' '))
1996 err = QXmlStream::tr(
"Invalid XML version string.");
1998 err = QXmlStream::tr(
"Unsupported XML version.");
2000 qsizetype n = attributeStack.size();
2003
2004
2005
2007 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2008 Attribute &attrib = attributeStack[i];
2009 XmlStringRef prefix(symPrefix(attrib.key));
2010 XmlStringRef key(symString(attrib.key));
2011 XmlStringRef value(symString(attrib.value));
2013 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2014 documentEncoding = value;
2017 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2018 if (!QXmlUtils::isEncName(value))
2019 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2021 QByteArray enc = value.toString().toUtf8();
2022 if (!lockEncoding) {
2023 decoder = QStringDecoder(enc.constData());
2024 if (!decoder.isValid()) {
2028 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2029 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2031 decoder = QStringDecoder(QStringDecoder::Utf8);
2032 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2038 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2039 if (!decoder.hasError())
2040 readBuffer = std::move(buf);
2044 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2045 hasStandalone =
true;
2046 if (value ==
"yes"_L1)
2048 else if (value ==
"no"_L1)
2051 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2053 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2058 raiseWellFormedError(err);
2059 attributeStack.clear();
2063void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2065 this->error = error;
2066 errorString = message;
2067 if (errorString.isNull()) {
2068 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2069 errorString = QXmlStream::tr(
"Premature end of document.");
2070 else if (error == QXmlStreamReader::CustomError)
2071 errorString = QXmlStream::tr(
"Invalid document.");
2074 type = QXmlStreamReader::Invalid;
2077void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2079 raiseError(QXmlStreamReader::NotWellFormedError, message);
2082void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2085 raiseError(QXmlStreamReader::NotWellFormedError,
2086 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2090void QXmlStreamReaderPrivate::parseError()
2093 if (token == EOF_SYMBOL) {
2094 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2098 QString error_message;
2099 int ers = state_stack[tos];
2102 if (token != XML_ERROR)
2103 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2104 int k = t_action(ers, tk);
2108 if (nexpected < nmax)
2109 expected[nexpected++] = tk;
2113 if (nexpected && nexpected < nmax) {
2115 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2116 .arg(QLatin1StringView(spell[expected[0]]));
2117 if (nexpected == 2) {
2119 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2120 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2121 }
else if (nexpected > 2) {
2123 for (; s < nexpected - 1; ++s) {
2125 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2126 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2129 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2130 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2132 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2133 .arg(exp_str, QLatin1StringView(spell[token]));
2135 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2138 raiseWellFormedError(error_message);
2141void QXmlStreamReaderPrivate::resume(
int rule) {
2142 resumeReduction = rule;
2143 if (error == QXmlStreamReader::NoError)
2144 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2148
2149
2150
2151qint64 QXmlStreamReader::lineNumber()
const
2153 Q_D(
const QXmlStreamReader);
2154 return d->lineNumber + 1;
2158
2159
2160
2161qint64 QXmlStreamReader::columnNumber()
const
2163 Q_D(
const QXmlStreamReader);
2164 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2168
2169
2170
2171qint64 QXmlStreamReader::characterOffset()
const
2173 Q_D(
const QXmlStreamReader);
2174 return d->characterOffset + d->readBufferPos;
2179
2180
2181QStringView QXmlStreamReader::text()
const
2183 Q_D(
const QXmlStreamReader);
2189
2190
2191
2192
2193
2194QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2196 Q_D(
const QXmlStreamReader);
2197 if (d->notationDeclarations.size())
2198 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2199 return d->publicNotationDeclarations;
2204
2205
2206
2207
2208
2209QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2211 Q_D(
const QXmlStreamReader);
2212 if (d->entityDeclarations.size())
2213 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2214 return d->publicEntityDeclarations;
2218
2219
2220
2221
2222
2223
2224QStringView QXmlStreamReader::dtdName()
const
2226 Q_D(
const QXmlStreamReader);
2227 if (d->type == QXmlStreamReader::DTD)
2229 return QStringView();
2233
2234
2235
2236
2237
2238
2239QStringView QXmlStreamReader::dtdPublicId()
const
2241 Q_D(
const QXmlStreamReader);
2242 if (d->type == QXmlStreamReader::DTD)
2243 return d->dtdPublicId;
2244 return QStringView();
2248
2249
2250
2251
2252
2253
2254QStringView QXmlStreamReader::dtdSystemId()
const
2256 Q_D(
const QXmlStreamReader);
2257 if (d->type == QXmlStreamReader::DTD)
2258 return d->dtdSystemId;
2259 return QStringView();
2263
2264
2265
2266
2267
2268
2269
2270
2271int QXmlStreamReader::entityExpansionLimit()
const
2273 Q_D(
const QXmlStreamReader);
2274 return d->entityExpansionLimit;
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2294 Q_D(QXmlStreamReader);
2295 d->entityExpansionLimit = limit;
2299
2300
2301
2302
2303
2304
2305
2306
2307QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2309 Q_D(
const QXmlStreamReader);
2310 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2311 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2312 return d->publicNamespaceDeclarations;
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2328 Q_D(QXmlStreamReader);
2329 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2330 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2331 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2335
2336
2337
2338
2339
2340
2341void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2343 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2344 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2367 Q_D(QXmlStreamReader);
2368 if (isStartElement()) {
2371 switch (readNext()) {
2373 case EntityReference:
2374 result.insert(result.size(), d->text);
2378 case ProcessingInstruction:
2382 if (behaviour == SkipChildElements) {
2383 skipCurrentElement();
2385 }
else if (behaviour == IncludeChildElements) {
2386 result += readElementText(behaviour);
2391 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2393 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2403
2404
2405
2406void QXmlStreamReader::raiseError(
const QString& message)
2408 Q_D(QXmlStreamReader);
2409 d->raiseError(CustomError, message);
2413
2414
2415
2416
2417QString QXmlStreamReader::errorString()
const
2419 Q_D(
const QXmlStreamReader);
2420 if (d->type == QXmlStreamReader::Invalid)
2421 return d->errorString;
2426
2427
2428
2429QXmlStreamReader::Error QXmlStreamReader::error()
const
2431 Q_D(
const QXmlStreamReader);
2432 if (d->type == QXmlStreamReader::Invalid)
2438
2439
2440QStringView QXmlStreamReader::processingInstructionTarget()
const
2442 Q_D(
const QXmlStreamReader);
2443 return d->processingInstructionTarget;
2447
2448
2449QStringView QXmlStreamReader::processingInstructionData()
const
2451 Q_D(
const QXmlStreamReader);
2452 return d->processingInstructionData;
2458
2459
2460
2461
2462QStringView QXmlStreamReader::name()
const
2464 Q_D(
const QXmlStreamReader);
2469
2470
2471
2472
2473QStringView QXmlStreamReader::namespaceUri()
const
2475 Q_D(
const QXmlStreamReader);
2476 return d->namespaceUri;
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491QStringView QXmlStreamReader::qualifiedName()
const
2493 Q_D(
const QXmlStreamReader);
2494 return d->qualifiedName;
2500
2501
2502
2503
2504
2505
2506QStringView QXmlStreamReader::prefix()
const
2508 Q_D(
const QXmlStreamReader);
2513
2514
2515QXmlStreamAttributes QXmlStreamReader::attributes()
const
2517 Q_D(
const QXmlStreamReader);
2518 return d->attributes;
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2541
2542
2543QXmlStreamAttribute::QXmlStreamAttribute()
2545 m_isDefault =
false;
2549
2550
2551QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2553 m_namespaceUri = namespaceUri;
2554 m_name = m_qualifiedName = name;
2556 m_namespaceUri = namespaceUri;
2560
2561
2562QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2564 qsizetype colon = qualifiedName.indexOf(u':');
2565 m_name = qualifiedName.mid(colon + 1);
2566 m_qualifiedName = qualifiedName;
2571
2572
2573
2574
2576
2577
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2590
2591
2592
2593
2594
2595
2596
2599
2600
2603
2604
2605
2606
2607
2609
2610
2611
2612
2614
2615
2616
2617
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2642
2643
2644
2645
2648
2649
2650
2651
2652
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2670
2671
2672QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2677
2678
2679
2681
2682
2683
2685
2686
2687
2690
2691
2692
2693
2695
2696
2697
2698
2701
2702
2703
2704
2705
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2721
2722
2723
2724
2726
2727
2728
2729
2732
2733
2734QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2739
2740
2741
2742
2743QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2746 m_namespaceUri = namespaceUri;
2750
2751
2752
2754
2755
2756
2762
2763
2764
2765
2766
2769
2770
2771
2772
2773
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2790
2791
2792QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2797
2798
2799
2801
2802
2803
2805
2806
2807
2809
2810
2811
2813
2814
2815
2818
2819
2820
2821
2823
2824
2825
2826
2829
2830
2831
2832
2833
2834
2835QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2837 for (
const QXmlStreamAttribute &attribute : *
this) {
2838 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2839 return attribute.value();
2841 return QStringView();
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2862 for (
const QXmlStreamAttribute &attribute : *
this) {
2863 if (attribute.qualifiedName() == qualifiedName)
2864 return attribute.value();
2866 return QStringView();
2870
2871
2872
2873void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2875 append(QXmlStreamAttribute(namespaceUri, name, value));
2879
2880
2881
2882void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
2884 append(QXmlStreamAttribute(qualifiedName, value));
2887#if QT_CONFIG(xmlstreamreader)
2890
2891
2893
2894
2896
2897
2899
2900
2902
2903
2904
2905
2907
2908
2910
2911
2913
2914
2916
2917
2920
2921
2922
2923
2924bool QXmlStreamReader::isWhitespace()
const
2926 Q_D(
const QXmlStreamReader);
2927 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
2931
2932
2933
2934
2935bool QXmlStreamReader::isCDATA()
const
2937 Q_D(
const QXmlStreamReader);
2938 return d->type == QXmlStreamReader::Characters && d->isCDATA;
2944
2945
2946
2947
2948
2949
2950
2951bool QXmlStreamReader::isStandaloneDocument()
const
2953 Q_D(
const QXmlStreamReader);
2954 return d->standalone;
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967bool QXmlStreamReader::hasStandaloneDeclaration()
const
2969 Q_D(
const QXmlStreamReader);
2970 return d->hasStandalone;
2974
2975
2976
2977
2978
2979
2980QStringView QXmlStreamReader::documentVersion()
const
2982 Q_D(
const QXmlStreamReader);
2983 if (d->type == QXmlStreamReader::StartDocument)
2984 return d->documentVersion;
2985 return QStringView();
2989
2990
2991
2992
2993
2994
2995QStringView QXmlStreamReader::documentEncoding()
const
2997 Q_D(
const QXmlStreamReader);
2998 if (d->type == QXmlStreamReader::StartDocument)
2999 return d->documentEncoding;
3000 return QStringView();
3006
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
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3121#if QT_CONFIG(xmlstreamwriter)
3123class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3125 QXmlStreamWriter *q_ptr;
3126 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3128 enum class StartElementOption {
3130 OmitNamespaceDeclarations = 1,
3133 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3134 ~QXmlStreamWriterPrivate() {
3139 void raiseError(QXmlStreamWriter::Error error);
3140 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3141 void write(QAnyStringView s);
3142 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3143 bool finishStartElement(
bool contents =
true);
3144 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3145 StartElementOption option = StartElementOption::KeepEverything);
3146 QIODevice *device =
nullptr;
3147 QString *stringDevice =
nullptr;
3148 uint deleteDevice :1;
3149 uint inStartElement :1;
3150 uint inEmptyElement :1;
3151 uint lastWasStartElement :1;
3152 uint wroteSomething :1;
3153 uint autoFormatting :1;
3154 uint didWriteStartDocument :1;
3155 uint didWriteAnyToken :1;
3156 uint stopWritingOnError :1;
3157 std::string autoFormattingIndent = std::string(4,
' ');
3158 NamespaceDeclaration emptyNamespace;
3159 qsizetype lastNamespaceDeclaration = 1;
3160 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3161 QString errorString;
3163 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3164 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3165 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3167 int namespacePrefixCount = 0;
3169 void indent(
int level);
3171 void doWriteToDevice(QStringView s);
3172 void doWriteToDevice(QUtf8StringView s);
3173 void doWriteToDevice(QLatin1StringView s);
3177QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3178 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3179 inEmptyElement(
false), lastWasStartElement(
false),
3180 wroteSomething(
false), autoFormatting(
false),
3181 didWriteStartDocument(
false), didWriteAnyToken(
false),
3182 stopWritingOnError(
false)
3186void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3190 case QXmlStreamWriter::Error::IO:
3191 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3193 case QXmlStreamWriter::Error::Encoding:
3194 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3196 case QXmlStreamWriter::Error::InvalidCharacter:
3197 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3199 case QXmlStreamWriter::Error::Custom:
3200 errorString = QXmlStream::tr(
"An error occurred while writing");
3202 case QXmlStreamWriter::Error::None:
3203 errorString.clear();
3208void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3211 errorString = message.toString();
3214void QXmlStreamWriterPrivate::write(QAnyStringView s)
3216 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3219 if (error == QXmlStreamWriter::Error::IO)
3222 s.visit([&] (
auto s) { doWriteToDevice(s); });
3223 }
else if (stringDevice) {
3224 s.visit([&] (
auto s) { stringDevice->append(s); });
3226 qWarning(
"QXmlStreamWriter: No device");
3230void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3237 NextResult operator()(
const char *&it,
const char *)
const
3238 {
return {uchar(*it++),
false}; }
3241 NextResult operator()(
const char *&it,
const char *end)
const
3245 constexpr char32_t invalidValue = 0xFFFFFFFF;
3246 static_assert(invalidValue > QChar::LastValidCodePoint);
3247 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3248 const auto old_i = i;
3249 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3250 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3252 return result == invalidValue ? NextResult{U'\0',
true}
3253 : NextResult{result,
false};
3257 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3259 QStringIterator decoder(it, end);
3262 constexpr char32_t invalidValue = 0xFFFFFFFF;
3263 static_assert(invalidValue > QChar::LastValidCodePoint);
3264 char32_t result = decoder.next(invalidValue);
3265 it = decoder.position();
3266 return result == invalidValue ? NextResult{U'\0',
true}
3267 : NextResult{result,
false};
3272 escaped.reserve(s.size());
3273 s.visit([&] (
auto s) {
3274 using View =
decltype(s);
3275 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3276 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3278 auto it = s.begin();
3279 const auto end = s.end();
3283 QLatin1StringView replacement;
3288 const auto decoded = decoder(next_it, end);
3289 switch (decoded.value) {
3291 replacement =
"<"_L1;
3294 replacement =
">"_L1;
3297 replacement =
"&"_L1;
3300 replacement =
"""_L1;
3303 if (escapeWhitespace)
3304 replacement =
"	"_L1;
3307 if (escapeWhitespace)
3308 replacement =
" "_L1;
3311 if (escapeWhitespace)
3312 replacement =
" "_L1;
3316 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3317 if (stopWritingOnError)
3319 replacement =
""_L1;
3320 Q_ASSERT(!replacement.isNull());
3323 if (decoded.value > 0x1F)
3329 raiseError(decoded.encodingError
3330 ? QXmlStreamWriter::Error::Encoding
3331 : QXmlStreamWriter::Error::InvalidCharacter);
3332 if (stopWritingOnError)
3334 replacement =
""_L1;
3335 Q_ASSERT(!replacement.isNull());
3338 if (!replacement.isNull())
3343 escaped.append(View{mark, it});
3344 escaped.append(replacement);
3353void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3354 if (namespaceDeclaration.prefix.isEmpty()) {
3356 write(namespaceDeclaration.namespaceUri);
3360 write(namespaceDeclaration.prefix);
3362 write(namespaceDeclaration.namespaceUri);
3365 didWriteAnyToken =
true;
3368bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3370 bool hadSomethingWritten = wroteSomething;
3371 wroteSomething = contents;
3372 if (!inStartElement)
3373 return hadSomethingWritten;
3375 if (inEmptyElement) {
3377 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3378 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3379 lastWasStartElement =
false;
3383 inStartElement = inEmptyElement =
false;
3384 lastNamespaceDeclaration = namespaceDeclarations.size();
3385 didWriteAnyToken =
true;
3386 return hadSomethingWritten;
3389QXmlStreamPrivateTagStack::NamespaceDeclaration &
3390QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3392 const bool prefixIsXml = prefix ==
"xml"_L1;
3393 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3394 if (prefixIsXml && !namespaceUriIsXml) {
3395 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3396 "than 'http://www.w3.org/XML/1998/namespace'");
3397 }
else if (!prefixIsXml && namespaceUriIsXml) {
3398 const QString prefixString = prefix.toString();
3399 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3400 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3401 qUtf16Printable(prefixString));
3403 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3404 const QString prefixString = prefix.toString();
3405 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3406 "'http://www.w3.org/2000/xmlns/'",
3407 qUtf16Printable(prefixString));
3409 auto &namespaceDeclaration = namespaceDeclarations.push();
3410 namespaceDeclaration.prefix = addToStringStorage(prefix);
3411 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3412 return namespaceDeclaration;
3415QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3417 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3418 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3419 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3420 return namespaceDeclaration;
3423 if (namespaceUri.isEmpty())
3424 return emptyNamespace;
3425 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3426 if (namespaceUri.isEmpty()) {
3427 namespaceDeclaration.prefix.clear();
3430 int n = ++namespacePrefixCount;
3432 s = u'n' + QString::number(n++);
3433 qsizetype j = namespaceDeclarations.size() - 2;
3434 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3439 namespaceDeclaration.prefix = addToStringStorage(s);
3441 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3442 if (writeDeclaration)
3443 writeNamespaceDeclaration(namespaceDeclaration);
3444 return namespaceDeclaration;
3449void QXmlStreamWriterPrivate::indent(
int level)
3451 if (didWriteStartDocument || didWriteAnyToken)
3453 for (
int i = 0; i < level; ++i)
3454 write(autoFormattingIndent);
3457void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3459 constexpr qsizetype MaxChunkSize = 512;
3460 char buffer [3 * MaxChunkSize];
3461 QStringEncoder::State state;
3462 while (!s.isEmpty()) {
3463 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3464 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3465 doWriteToDevice(QUtf8StringView{buffer, end});
3466 s = s.sliced(chunkSize);
3468 if (state.remainingChars > 0)
3469 raiseError(QXmlStreamWriter::Error::Encoding);
3472void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3474 QByteArrayView bytes = s;
3475 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3476 raiseError(QXmlStreamWriter::Error::IO);
3479void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3481 constexpr qsizetype MaxChunkSize = 512;
3482 char buffer [2 * MaxChunkSize];
3483 while (!s.isEmpty()) {
3484 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3485 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3486 doWriteToDevice(QUtf8StringView{buffer, end});
3487 s = s.sliced(chunkSize);
3492
3493
3494
3495
3496QXmlStreamWriter::QXmlStreamWriter()
3497 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3502
3503
3504QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3505 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3507 Q_D(QXmlStreamWriter);
3512
3513
3514
3515QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3516 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3518 Q_D(QXmlStreamWriter);
3519 d->device =
new QBuffer(array);
3520 d->device->open(QIODevice::WriteOnly);
3521 d->deleteDevice =
true;
3526
3527QXmlStreamWriter::QXmlStreamWriter(QString *string)
3528 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3530 Q_D(QXmlStreamWriter);
3531 d->stringDevice = string;
3535
3536
3537QXmlStreamWriter::~QXmlStreamWriter()
3543
3544
3545
3546
3547
3548void QXmlStreamWriter::setDevice(QIODevice *device)
3550 Q_D(QXmlStreamWriter);
3551 if (device == d->device)
3553 d->stringDevice =
nullptr;
3554 if (d->deleteDevice) {
3556 d->deleteDevice =
false;
3562
3563
3564
3565
3566
3567QIODevice *QXmlStreamWriter::device()
const
3569 Q_D(
const QXmlStreamWriter);
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3590
3591
3592
3593
3594
3595
3596
3597void QXmlStreamWriter::setAutoFormatting(
bool enable)
3599 Q_D(QXmlStreamWriter);
3600 d->autoFormatting = enable;
3604
3605
3606
3607
3608bool QXmlStreamWriter::autoFormatting()
const
3610 Q_D(
const QXmlStreamWriter);
3611 return d->autoFormatting;
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3628void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3630 Q_D(QXmlStreamWriter);
3631 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3634int QXmlStreamWriter::autoFormattingIndent()
const
3636 Q_D(
const QXmlStreamWriter);
3637 const QLatin1StringView indent(d->autoFormattingIndent);
3638 return indent.count(u' ') - indent.count(u'\t');
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658bool QXmlStreamWriter::stopWritingOnError()
const
3660 Q_D(
const QXmlStreamWriter);
3661 return d->stopWritingOnError;
3664void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3666 Q_D(QXmlStreamWriter);
3667 d->stopWritingOnError = stop;
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682bool QXmlStreamWriter::hasError()
const
3684 return error() != QXmlStreamWriter::Error::None;
3688
3689
3690
3691
3692
3693
3694
3695
3696QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3698 Q_D(
const QXmlStreamWriter);
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712QString QXmlStreamWriter::errorString()
const
3714 Q_D(
const QXmlStreamWriter);
3715 return d->errorString;
3719
3720
3721
3722
3723
3724
3725
3726
3727void QXmlStreamWriter::raiseError(QAnyStringView message)
3729 Q_D(QXmlStreamWriter);
3730 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3746 Q_D(QXmlStreamWriter);
3747 Q_ASSERT(d->inStartElement);
3748 Q_ASSERT(count(qualifiedName,
':') <= 1);
3750 d->write(qualifiedName);
3752 d->writeEscaped(value,
true);
3754 d->didWriteAnyToken =
true;
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3770 Q_D(QXmlStreamWriter);
3771 Q_ASSERT(d->inStartElement);
3772 Q_ASSERT(!contains(name,
':'));
3773 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3775 if (!namespaceDeclaration.prefix.isEmpty()) {
3776 d->write(namespaceDeclaration.prefix);
3781 d->writeEscaped(value,
true);
3783 d->didWriteAnyToken =
true;
3787
3788
3789
3790
3791
3792
3793
3794void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3796 if (attribute.namespaceUri().isEmpty())
3797 writeAttribute(attribute.qualifiedName(), attribute.value());
3799 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3804
3805
3806
3807
3808
3809
3810
3811
3812void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3814 Q_D(QXmlStreamWriter);
3815 Q_ASSERT(d->inStartElement);
3817 for (
const auto &attr : attributes)
3818 writeAttribute(attr);
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3835 Q_D(QXmlStreamWriter);
3836 d->finishStartElement();
3837 d->write(
"<![CDATA[");
3838 while (!text.isEmpty()) {
3839 const auto idx = indexOf(text,
"]]>"_L1);
3842 d->write(text.first(idx));
3846 text = text.sliced(idx + 3);
3854
3855
3856
3857
3858
3859
3860
3861
3862void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3864 Q_D(QXmlStreamWriter);
3865 d->finishStartElement();
3866 d->writeEscaped(text);
3871
3872
3873
3874
3875
3876
3877void QXmlStreamWriter::writeComment(QAnyStringView text)
3879 Q_D(QXmlStreamWriter);
3880 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
3881 if (!d->finishStartElement(
false) && d->autoFormatting)
3882 d->indent(d->tagStack.size());
3886 d->inStartElement = d->lastWasStartElement =
false;
3891
3892
3893
3894
3895
3896void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
3898 Q_D(QXmlStreamWriter);
3899 d->finishStartElement();
3900 if (d->autoFormatting)
3903 if (d->autoFormatting)
3910
3911
3912
3913
3914
3915
3916void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
3918 Q_D(QXmlStreamWriter);
3919 Q_ASSERT(count(qualifiedName,
':') <= 1);
3920 d->writeStartElement({}, qualifiedName);
3921 d->inEmptyElement =
true;
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
3937 Q_D(QXmlStreamWriter);
3938 Q_ASSERT(!contains(name,
':'));
3939 d->writeStartElement(namespaceUri, name);
3940 d->inEmptyElement =
true;
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
3956 writeStartElement(qualifiedName);
3957 writeCharacters(text);
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
3975 writeStartElement(namespaceUri, name);
3976 writeCharacters(text);
3982
3983
3984
3985
3986void QXmlStreamWriter::writeEndDocument()
3988 Q_D(QXmlStreamWriter);
3989 while (d->tagStack.size())
3991 if (d->didWriteStartDocument || d->didWriteAnyToken)
3996
3997
3998
3999
4000void QXmlStreamWriter::writeEndElement()
4002 Q_D(QXmlStreamWriter);
4003 Q_ASSERT(d->didWriteAnyToken);
4004 if (d->tagStack.isEmpty())
4008 if (d->inStartElement && !d->inEmptyElement) {
4010 d->lastWasStartElement = d->inStartElement =
false;
4011 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4012 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4016 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4017 d->indent(d->tagStack.size()-1);
4018 if (d->tagStack.isEmpty())
4020 d->lastWasStartElement =
false;
4021 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4022 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4024 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4025 d->write(tag.namespaceDeclaration.prefix);
4035
4036
4037
4038
4039
4040void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4042 Q_D(QXmlStreamWriter);
4043 d->finishStartElement();
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4069 Q_D(QXmlStreamWriter);
4070 Q_ASSERT(prefix !=
"xmlns"_L1);
4071 if (prefix.isEmpty()) {
4072 d->findNamespace(namespaceUri, d->inStartElement);
4074 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4075 if (d->inStartElement)
4076 d->writeNamespaceDeclaration(namespaceDeclaration);
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4096 Q_D(QXmlStreamWriter);
4097 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4098 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4099 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4100 namespaceDeclaration.prefix.clear();
4101 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4102 if (d->inStartElement)
4103 d->writeNamespaceDeclaration(namespaceDeclaration);
4108
4109
4110
4111
4112
4113
4114void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4116 Q_D(QXmlStreamWriter);
4117 Q_ASSERT(!contains(data,
"?>"_L1));
4118 if (!d->finishStartElement(
false) && d->autoFormatting)
4119 d->indent(d->tagStack.size());
4122 if (!data.isNull()) {
4127 d->didWriteAnyToken =
true;
4133
4134
4135
4136
4137
4138
4139void QXmlStreamWriter::writeStartDocument()
4141 writeStartDocument(
"1.0"_L1);
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4163 Q_D(QXmlStreamWriter);
4164 d->finishStartElement(
false);
4165 d->write(
"<?xml version=\"");
4168 d->write(
"\" encoding=\"UTF-8");
4170 d->didWriteStartDocument =
true;
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4193 Q_D(QXmlStreamWriter);
4194 d->finishStartElement(
false);
4195 d->write(
"<?xml version=\"");
4198 d->write(
"\" encoding=\"UTF-8");
4200 d->write(
"\" standalone=\"yes\"?>");
4202 d->write(
"\" standalone=\"no\"?>");
4203 d->didWriteStartDocument =
true;
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4219 Q_D(QXmlStreamWriter);
4220 Q_ASSERT(count(qualifiedName,
':') <= 1);
4221 d->writeStartElement({}, qualifiedName);
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4238 Q_D(QXmlStreamWriter);
4239 Q_ASSERT(!contains(name,
':'));
4240 d->writeStartElement(namespaceUri, name);
4243void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4244 StartElementOption option)
4246 if (!finishStartElement(
false) && autoFormatting)
4247 indent(tagStack.size());
4249 Tag &tag = tagStack_push();
4250 tag.name = addToStringStorage(name);
4251 tag.namespaceDeclaration = findNamespace(namespaceUri);
4253 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4254 write(tag.namespaceDeclaration.prefix);
4258 inStartElement = lastWasStartElement =
true;
4260 if (option != StartElementOption::OmitNamespaceDeclarations) {
4261 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4262 writeNamespaceDeclaration(namespaceDeclarations[i]);
4264 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4265 didWriteAnyToken =
true;
4268#if QT_CONFIG(xmlstreamreader)
4270
4271
4272
4273
4274
4275
4276void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4278 Q_D(QXmlStreamWriter);
4279 switch (reader.tokenType()) {
4280 case QXmlStreamReader::NoToken:
4282 case QXmlStreamReader::StartDocument:
4283 writeStartDocument();
4285 case QXmlStreamReader::EndDocument:
4288 case QXmlStreamReader::StartElement: {
4290 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4291 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4292 for (
const auto &namespaceDeclaration : nsDeclarations) {
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