1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "QtCore/qxmlstream.h"
41
42#ifndef QT_NO_XMLSTREAM
43
44#include "qxmlutils_p.h"
45#include <qdebug.h>
46#include <qfile.h>
47#include <stdio.h>
48#if QT_CONFIG(textcodec)
49#include <qtextcodec.h>
50#endif
51#include <qstack.h>
52#include <qbuffer.h>
53#include <qscopeguard.h>
54#ifndef QT_BOOTSTRAPPED
55#include <qcoreapplication.h>
56#else
57// This specialization of Q_DECLARE_TR_FUNCTIONS is not in qcoreapplication.h,
58// because that header depends on QObject being available, which is not the
59// case for most bootstrapped applications.
60#define Q_DECLARE_TR_FUNCTIONS(context) \
61public: \
62 static inline QString tr(const char *sourceText, const char *comment = nullptr) \
63 { Q_UNUSED(comment); return QString::fromLatin1(sourceText); } \
64 static inline QString trUtf8(const char *sourceText, const char *comment = nullptr) \
65 { Q_UNUSED(comment); return QString::fromLatin1(sourceText); } \
66 static inline QString tr(const char *sourceText, const char*, int) \
67 { return QString::fromLatin1(sourceText); } \
68 static inline QString trUtf8(const char *sourceText, const char*, int) \
69 { return QString::fromLatin1(sourceText); } \
70private:
71#endif
72#include <private/qmemory_p.h>
73
74QT_BEGIN_NAMESPACE
75
76#include "qxmlstream_p.h"
77
78enum { StreamEOF = ~0U };
79
80/*!
81 \enum QXmlStreamReader::TokenType
82
83 This enum specifies the type of token the reader just read.
84
85 \value NoToken The reader has not yet read anything.
86
87 \value Invalid An error has occurred, reported in error() and
88 errorString().
89
90 \value StartDocument The reader reports the XML version number in
91 documentVersion(), and the encoding as specified in the XML
92 document in documentEncoding(). If the document is declared
93 standalone, isStandaloneDocument() returns \c true; otherwise it
94 returns \c false.
95
96 \value EndDocument The reader reports the end of the document.
97
98 \value StartElement The reader reports the start of an element
99 with namespaceUri() and name(). Empty elements are also reported
100 as StartElement, followed directly by EndElement. The convenience
101 function readElementText() can be called to concatenate all
102 content until the corresponding EndElement. Attributes are
103 reported in attributes(), namespace declarations in
104 namespaceDeclarations().
105
106 \value EndElement The reader reports the end of an element with
107 namespaceUri() and name().
108
109 \value Characters The reader reports characters in text(). If the
110 characters are all white-space, isWhitespace() returns \c true. If
111 the characters stem from a CDATA section, isCDATA() returns \c true.
112
113 \value Comment The reader reports a comment in text().
114
115 \value DTD The reader reports a DTD in text(), notation
116 declarations in notationDeclarations(), and entity declarations in
117 entityDeclarations(). Details of the DTD declaration are reported
118 in in dtdName(), dtdPublicId(), and dtdSystemId().
119
120 \value EntityReference The reader reports an entity reference that
121 could not be resolved. The name of the reference is reported in
122 name(), the replacement text in text().
123
124 \value ProcessingInstruction The reader reports a processing
125 instruction in processingInstructionTarget() and
126 processingInstructionData().
127*/
128
129/*!
130 \enum QXmlStreamReader::ReadElementTextBehaviour
131
132 This enum specifies the different behaviours of readElementText().
133
134 \value ErrorOnUnexpectedElement Raise an UnexpectedElementError and return
135 what was read so far when a child element is encountered.
136
137 \value IncludeChildElements Recursively include the text from child elements.
138
139 \value SkipChildElements Skip child elements.
140
141 \since 4.6
142*/
143
144/*!
145 \enum QXmlStreamReader::Error
146
147 This enum specifies different error cases
148
149 \value NoError No error has occurred.
150
151 \value CustomError A custom error has been raised with
152 raiseError()
153
154 \value NotWellFormedError The parser internally raised an error
155 due to the read XML not being well-formed.
156
157 \value PrematureEndOfDocumentError The input stream ended before a
158 well-formed XML document was parsed. Recovery from this error is
159 possible if more XML arrives in the stream, either by calling
160 addData() or by waiting for it to arrive on the device().
161
162 \value UnexpectedElementError The parser encountered an element
163 that was different to those it expected.
164
165*/
166
167/*!
168 \class QXmlStreamEntityResolver
169 \inmodule QtCore
170 \reentrant
171 \since 4.4
172
173 \brief The QXmlStreamEntityResolver class provides an entity
174 resolver for a QXmlStreamReader.
175
176 \ingroup xml-tools
177 */
178
179/*!
180 Destroys the entity resolver.
181 */
182QXmlStreamEntityResolver::~QXmlStreamEntityResolver()
183{
184}
185
186/*!
187 \internal
188
189This function is a stub for later functionality.
190*/
191QString QXmlStreamEntityResolver::resolveEntity(const QString& /*publicId*/, const QString& /*systemId*/)
192{
193 return QString();
194}
195
196
197/*!
198 Resolves the undeclared entity \a name and returns its replacement
199 text. If the entity is also unknown to the entity resolver, it
200 returns an empty string.
201
202 The default implementation always returns an empty string.
203*/
204
205QString QXmlStreamEntityResolver::resolveUndeclaredEntity(const QString &/*name*/)
206{
207 return QString();
208}
209
210#ifndef QT_NO_XMLSTREAMREADER
211
212QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(const QString &name)
213{
214 if (entityResolver)
215 return entityResolver->resolveUndeclaredEntity(name);
216 return QString();
217}
218
219
220
221/*!
222 \since 4.4
223
224 Makes \a resolver the new entityResolver().
225
226 The stream reader does \e not take ownership of the resolver. It's
227 the callers responsibility to ensure that the resolver is valid
228 during the entire life-time of the stream reader object, or until
229 another resolver or \nullptr is set.
230
231 \sa entityResolver()
232 */
233void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
234{
235 Q_D(QXmlStreamReader);
236 d->entityResolver = resolver;
237}
238
239/*!
240 \since 4.4
241
242 Returns the entity resolver, or \nullptr if there is no entity resolver.
243
244 \sa setEntityResolver()
245 */
246QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
247{
248 Q_D(const QXmlStreamReader);
249 return d->entityResolver;
250}
251
252
253
254/*!
255 \class QXmlStreamReader
256 \inmodule QtCore
257 \reentrant
258 \since 4.3
259
260 \brief The QXmlStreamReader class provides a fast parser for reading
261 well-formed XML via a simple streaming API.
262
263
264 \ingroup xml-tools
265
266 QXmlStreamReader provides a simple streaming API to parse well-formed
267 XML. It is an alternative to first loading the complete XML into a
268 DOM tree (see \l QDomDocument). QXmlStreamReader reads data either
269 from a QIODevice (see setDevice()), or from a raw QByteArray (see addData()).
270
271 Qt provides QXmlStreamWriter for writing XML.
272
273 The basic concept of a stream reader is to report an XML document as
274 a stream of tokens, similar to SAX. The main difference between
275 QXmlStreamReader and SAX is \e how these XML tokens are reported.
276 With SAX, the application must provide handlers (callback functions)
277 that receive so-called XML \e events from the parser at the parser's
278 convenience. With QXmlStreamReader, the application code itself
279 drives the loop and pulls \e tokens from the reader, one after
280 another, as it needs them. This is done by calling readNext(), where
281 the reader reads from the input stream until it completes the next
282 token, at which point it returns the tokenType(). A set of
283 convenient functions including isStartElement() and text() can then
284 be used to examine the token to obtain information about what has
285 been read. The big advantage of this \e pulling approach is the
286 possibility to build recursive descent parsers with it, meaning you
287 can split your XML parsing code easily into different methods or
288 classes. This makes it easy to keep track of the application's own
289 state when parsing XML.
290
291 A typical loop with QXmlStreamReader looks like this:
292
293 \snippet code/src_corelib_xml_qxmlstream.cpp 0
294
295
296 QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
297 include external parsed entities. As long as no error occurs, the
298 application code can thus be assured that the data provided by the
299 stream reader satisfies the W3C's criteria for well-formed XML. For
300 example, you can be certain that all tags are indeed nested and
301 closed properly, that references to internal entities have been
302 replaced with the correct replacement text, and that attributes have
303 been normalized or added according to the internal subset of the
304 DTD.
305
306 If an error occurs while parsing, atEnd() and hasError() return
307 true, and error() returns the error that occurred. The functions
308 errorString(), lineNumber(), columnNumber(), and characterOffset()
309 are for constructing an appropriate error or warning message. To
310 simplify application code, QXmlStreamReader contains a raiseError()
311 mechanism that lets you raise custom errors that trigger the same
312 error handling described.
313
314 The \l{QXmlStream Bookmarks Example} illustrates how to use the
315 recursive descent technique to read an XML bookmark file (XBEL) with
316 a stream reader.
317
318 \section1 Namespaces
319
320 QXmlStream understands and resolves XML namespaces. E.g. in case of
321 a StartElement, namespaceUri() returns the namespace the element is
322 in, and name() returns the element's \e local name. The combination
323 of namespaceUri and name uniquely identifies an element. If a
324 namespace prefix was not declared in the XML entities parsed by the
325 reader, the namespaceUri is empty.
326
327 If you parse XML data that does not utilize namespaces according to
328 the XML specification or doesn't use namespaces at all, you can use
329 the element's qualifiedName() instead. A qualified name is the
330 element's prefix() followed by colon followed by the element's local
331 name() - exactly like the element appears in the raw XML data. Since
332 the mapping namespaceUri to prefix is neither unique nor universal,
333 qualifiedName() should be avoided for namespace-compliant XML data.
334
335 In order to parse standalone documents that do use undeclared
336 namespace prefixes, you can turn off namespace processing completely
337 with the \l namespaceProcessing property.
338
339 \section1 Incremental Parsing
340
341 QXmlStreamReader is an incremental parser. It can handle the case
342 where the document can't be parsed all at once because it arrives in
343 chunks (e.g. from multiple files, or over a network connection).
344 When the reader runs out of data before the complete document has
345 been parsed, it reports a PrematureEndOfDocumentError. When more
346 data arrives, either because of a call to addData() or because more
347 data is available through the network device(), the reader recovers
348 from the PrematureEndOfDocumentError error and continues parsing the
349 new data with the next call to readNext().
350
351 For example, if your application reads data from the network using a
352 \l{QNetworkAccessManager} {network access manager}, you would issue
353 a \l{QNetworkRequest} {network request} to the manager and receive a
354 \l{QNetworkReply} {network reply} in return. Since a QNetworkReply
355 is a QIODevice, you connect its \l{QIODevice::readyRead()}
356 {readyRead()} signal to a custom slot, e.g. \c{slotReadyRead()} in
357 the code snippet shown in the discussion for QNetworkAccessManager.
358 In this slot, you read all available data with
359 \l{QIODevice::readAll()} {readAll()} and pass it to the XML
360 stream reader using addData(). Then you call your custom parsing
361 function that reads the XML events from the reader.
362
363 \section1 Performance and Memory Consumption
364
365 QXmlStreamReader is memory-conservative by design, since it doesn't
366 store the entire XML document tree in memory, but only the current
367 token at the time it is reported. In addition, QXmlStreamReader
368 avoids the many small string allocations that it normally takes to
369 map an XML document to a convenient and Qt-ish API. It does this by
370 reporting all string data as QStringRef rather than real QString
371 objects. QStringRef is a thin wrapper around QString substrings that
372 provides a subset of the QString API without the memory allocation
373 and reference-counting overhead. Calling
374 \l{QStringRef::toString()}{toString()} on any of those objects
375 returns an equivalent real QString object.
376
377*/
378
379
380/*!
381 Constructs a stream reader.
382
383 \sa setDevice(), addData()
384 */
385QXmlStreamReader::QXmlStreamReader()
386 : d_ptr(new QXmlStreamReaderPrivate(this))
387{
388}
389
390/*! Creates a new stream reader that reads from \a device.
391
392\sa setDevice(), clear()
393 */
394QXmlStreamReader::QXmlStreamReader(QIODevice *device)
395 : d_ptr(new QXmlStreamReaderPrivate(this))
396{
397 setDevice(device);
398}
399
400/*!
401 Creates a new stream reader that reads from \a data.
402
403 \sa addData(), clear(), setDevice()
404 */
405QXmlStreamReader::QXmlStreamReader(const QByteArray &data)
406 : d_ptr(new QXmlStreamReaderPrivate(this))
407{
408 Q_D(QXmlStreamReader);
409 d->dataBuffer = data;
410}
411
412/*!
413 Creates a new stream reader that reads from \a data.
414
415 This function should only be used if the XML header either says the encoding
416 is "UTF-8" or lacks any encoding information (the latter is the case of
417 QXmlStreamWriter writing to a QString). Any other encoding is likely going to
418 cause data corruption ("mojibake").
419
420 \sa addData(), clear(), setDevice()
421 */
422QXmlStreamReader::QXmlStreamReader(const QString &data)
423 : d_ptr(new QXmlStreamReaderPrivate(this))
424{
425 Q_D(QXmlStreamReader);
426#if !QT_CONFIG(textcodec)
427 d->dataBuffer = data.toLatin1();
428#else
429 d->dataBuffer = d->codec->fromUnicode(uc: data);
430 d->decoder = d->codec->makeDecoder();
431#endif
432 d->lockEncoding = true;
433
434}
435
436/*!
437 Creates a new stream reader that reads from \a data.
438
439 \sa addData(), clear(), setDevice()
440 */
441QXmlStreamReader::QXmlStreamReader(const char *data)
442 : d_ptr(new QXmlStreamReaderPrivate(this))
443{
444 Q_D(QXmlStreamReader);
445 d->dataBuffer = QByteArray(data);
446}
447
448/*!
449 Destructs the reader.
450 */
451QXmlStreamReader::~QXmlStreamReader()
452{
453 Q_D(QXmlStreamReader);
454 if (d->deleteDevice)
455 delete d->device;
456}
457
458/*! \fn bool QXmlStreamReader::hasError() const
459 Returns \c true if an error has occurred, otherwise \c false.
460
461 \sa errorString(), error()
462 */
463
464/*!
465 Sets the current device to \a device. Setting the device resets
466 the stream to its initial state.
467
468 \sa device(), clear()
469*/
470void QXmlStreamReader::setDevice(QIODevice *device)
471{
472 Q_D(QXmlStreamReader);
473 if (d->deleteDevice) {
474 delete d->device;
475 d->deleteDevice = false;
476 }
477 d->device = device;
478 d->init();
479
480}
481
482/*!
483 Returns the current device associated with the QXmlStreamReader,
484 or \nullptr if no device has been assigned.
485
486 \sa setDevice()
487*/
488QIODevice *QXmlStreamReader::device() const
489{
490 Q_D(const QXmlStreamReader);
491 return d->device;
492}
493
494
495/*!
496 Adds more \a data for the reader to read. This function does
497 nothing if the reader has a device().
498
499 \sa readNext(), clear()
500 */
501void QXmlStreamReader::addData(const QByteArray &data)
502{
503 Q_D(QXmlStreamReader);
504 if (d->device) {
505 qWarning(msg: "QXmlStreamReader: addData() with device()");
506 return;
507 }
508 d->dataBuffer += data;
509}
510
511/*!
512 Adds more \a data for the reader to read. This function does
513 nothing if the reader has a device().
514
515 \sa readNext(), clear()
516 */
517void QXmlStreamReader::addData(const QString &data)
518{
519 Q_D(QXmlStreamReader);
520 d->lockEncoding = true;
521#if !QT_CONFIG(textcodec)
522 addData(data.toLatin1());
523#else
524 addData(data: d->codec->fromUnicode(uc: data));
525#endif
526}
527
528/*!
529 Adds more \a data for the reader to read. This function does
530 nothing if the reader has a device().
531
532 \sa readNext(), clear()
533 */
534void QXmlStreamReader::addData(const char *data)
535{
536 addData(data: QByteArray(data));
537}
538
539/*!
540 Removes any device() or data from the reader and resets its
541 internal state to the initial state.
542
543 \sa addData()
544 */
545void QXmlStreamReader::clear()
546{
547 Q_D(QXmlStreamReader);
548 d->init();
549 if (d->device) {
550 if (d->deleteDevice)
551 delete d->device;
552 d->device = nullptr;
553 }
554}
555
556/*!
557 Returns \c true if the reader has read until the end of the XML
558 document, or if an error() has occurred and reading has been
559 aborted. Otherwise, it returns \c false.
560
561 When atEnd() and hasError() return true and error() returns
562 PrematureEndOfDocumentError, it means the XML has been well-formed
563 so far, but a complete XML document has not been parsed. The next
564 chunk of XML can be added with addData(), if the XML is being read
565 from a QByteArray, or by waiting for more data to arrive if the
566 XML is being read from a QIODevice. Either way, atEnd() will
567 return false once more data is available.
568
569 \sa hasError(), error(), device(), QIODevice::atEnd()
570 */
571bool QXmlStreamReader::atEnd() const
572{
573 Q_D(const QXmlStreamReader);
574 if (d->atEnd
575 && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError)
576 || (d->type == QXmlStreamReader::EndDocument))) {
577 if (d->device)
578 return d->device->atEnd();
579 else
580 return !d->dataBuffer.size();
581 }
582 return (d->atEnd || d->type == QXmlStreamReader::Invalid);
583}
584
585
586/*!
587 Reads the next token and returns its type.
588
589 With one exception, once an error() is reported by readNext(),
590 further reading of the XML stream is not possible. Then atEnd()
591 returns \c true, hasError() returns \c true, and this function returns
592 QXmlStreamReader::Invalid.
593
594 The exception is when error() returns PrematureEndOfDocumentError.
595 This error is reported when the end of an otherwise well-formed
596 chunk of XML is reached, but the chunk doesn't represent a complete
597 XML document. In that case, parsing \e can be resumed by calling
598 addData() to add the next chunk of XML, when the stream is being
599 read from a QByteArray, or by waiting for more data to arrive when
600 the stream is being read from a device().
601
602 \sa tokenType(), tokenString()
603 */
604QXmlStreamReader::TokenType QXmlStreamReader::readNext()
605{
606 Q_D(QXmlStreamReader);
607 if (d->type != Invalid) {
608 if (!d->hasCheckedStartDocument)
609 if (!d->checkStartDocument())
610 return d->type; // synthetic StartDocument or error
611 d->parse();
612 if (d->atEnd && d->type != EndDocument && d->type != Invalid)
613 d->raiseError(error: PrematureEndOfDocumentError);
614 else if (!d->atEnd && d->type == EndDocument)
615 d->raiseWellFormedError(message: QXmlStream::tr(sourceText: "Extra content at end of document."));
616 } else if (d->error == PrematureEndOfDocumentError) {
617 // resume error
618 d->type = NoToken;
619 d->atEnd = false;
620 d->token = -1;
621 return readNext();
622 }
623 return d->type;
624}
625
626
627/*!
628 Returns the type of the current token.
629
630 The current token can also be queried with the convenience functions
631 isStartDocument(), isEndDocument(), isStartElement(),
632 isEndElement(), isCharacters(), isComment(), isDTD(),
633 isEntityReference(), and isProcessingInstruction().
634
635 \sa tokenString()
636 */
637QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const
638{
639 Q_D(const QXmlStreamReader);
640 return d->type;
641}
642
643/*!
644 Reads until the next start element within the current element. Returns \c true
645 when a start element was reached. When the end element was reached, or when
646 an error occurred, false is returned.
647
648 The current element is the element matching the most recently parsed start
649 element of which a matching end element has not yet been reached. When the
650 parser has reached the end element, the current element becomes the parent
651 element.
652
653 This is a convenience function for when you're only concerned with parsing
654 XML elements. The \l{QXmlStream Bookmarks Example} makes extensive use of
655 this function.
656
657 \since 4.6
658 \sa readNext()
659 */
660bool QXmlStreamReader::readNextStartElement()
661{
662 while (readNext() != Invalid) {
663 if (isEndElement())
664 return false;
665 else if (isStartElement())
666 return true;
667 }
668 return false;
669}
670
671/*!
672 Reads until the end of the current element, skipping any child nodes.
673 This function is useful for skipping unknown elements.
674
675 The current element is the element matching the most recently parsed start
676 element of which a matching end element has not yet been reached. When the
677 parser has reached the end element, the current element becomes the parent
678 element.
679
680 \since 4.6
681 */
682void QXmlStreamReader::skipCurrentElement()
683{
684 int depth = 1;
685 while (depth && readNext() != Invalid) {
686 if (isEndElement())
687 --depth;
688 else if (isStartElement())
689 ++depth;
690 }
691}
692
693/*
694 * Use the following Perl script to generate the error string index list:
695===== PERL SCRIPT ====
696print "static const char QXmlStreamReader_tokenTypeString_string[] =\n";
697$counter = 0;
698$i = 0;
699while (<STDIN>) {
700 chomp;
701 print " \"$_\\0\"\n";
702 $sizes[$i++] = $counter;
703 $counter += length 1 + $_;
704}
705print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n ";
706for ($j = 0; $j < $i; ++$j) {
707 printf "$sizes[$j], ";
708}
709print "0\n};\n";
710===== PERL SCRIPT ====
711
712 * The input data is as follows (copied from qxmlstream.h):
713NoToken
714Invalid
715StartDocument
716EndDocument
717StartElement
718EndElement
719Characters
720Comment
721DTD
722EntityReference
723ProcessingInstruction
724*/
725static const char QXmlStreamReader_tokenTypeString_string[] =
726 "NoToken\0"
727 "Invalid\0"
728 "StartDocument\0"
729 "EndDocument\0"
730 "StartElement\0"
731 "EndElement\0"
732 "Characters\0"
733 "Comment\0"
734 "DTD\0"
735 "EntityReference\0"
736 "ProcessingInstruction\0";
737
738static const short QXmlStreamReader_tokenTypeString_indices[] = {
739 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0
740};
741
742
743/*!
744 \property QXmlStreamReader::namespaceProcessing
745 The namespace-processing flag of the stream reader
746
747 This property controls whether or not the stream reader processes
748 namespaces. If enabled, the reader processes namespaces, otherwise
749 it does not.
750
751 By default, namespace-processing is enabled.
752*/
753
754
755void QXmlStreamReader::setNamespaceProcessing(bool enable)
756{
757 Q_D(QXmlStreamReader);
758 d->namespaceProcessing = enable;
759}
760
761bool QXmlStreamReader::namespaceProcessing() const
762{
763 Q_D(const QXmlStreamReader);
764 return d->namespaceProcessing;
765}
766
767/*! Returns the reader's current token as string.
768
769\sa tokenType()
770*/
771QString QXmlStreamReader::tokenString() const
772{
773 Q_D(const QXmlStreamReader);
774 return QLatin1String(QXmlStreamReader_tokenTypeString_string +
775 QXmlStreamReader_tokenTypeString_indices[d->type]);
776}
777
778#endif // QT_NO_XMLSTREAMREADER
779
780QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
781{
782 tagStack.reserve(extraCapacity: 16);
783 tagStackStringStorage.reserve(asize: 32);
784 tagStackStringStorageSize = 0;
785 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
786 namespaceDeclaration.prefix = addToStringStorage(s: u"xml");
787 namespaceDeclaration.namespaceUri = addToStringStorage(s: u"http://www.w3.org/XML/1998/namespace");
788 initialTagStackStringStorageSize = tagStackStringStorageSize;
789}
790
791#ifndef QT_NO_XMLSTREAMREADER
792
793QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
794 :q_ptr(q)
795{
796 device = nullptr;
797 deleteDevice = false;
798#if QT_CONFIG(textcodec)
799 decoder = nullptr;
800#endif
801 stack_size = 64;
802 sym_stack = nullptr;
803 state_stack = nullptr;
804 reallocateStack();
805 entityResolver = nullptr;
806 init();
807#define ADD_PREDEFINED(n, v) \
808 do { \
809 Entity e = Entity::createLiteral(QLatin1String(n), QLatin1String(v)); \
810 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e)); \
811 } while (false)
812 ADD_PREDEFINED("lt", "<");
813 ADD_PREDEFINED("gt", ">");
814 ADD_PREDEFINED("amp", "&");
815 ADD_PREDEFINED("apos", "'");
816 ADD_PREDEFINED("quot", "\"");
817#undef ADD_PREDEFINED
818}
819
820void QXmlStreamReaderPrivate::init()
821{
822 scanDtd = false;
823 token = -1;
824 token_char = 0;
825 isEmptyElement = false;
826 isWhitespace = true;
827 isCDATA = false;
828 standalone = false;
829 tos = 0;
830 resumeReduction = 0;
831 state_stack[tos++] = 0;
832 state_stack[tos] = 0;
833 putStack.clear();
834 putStack.reserve(extraCapacity: 32);
835 textBuffer.clear();
836 textBuffer.reserve(asize: 256);
837 tagStack.clear();
838 tagsDone = false;
839 attributes.clear();
840 attributes.reserve(asize: 16);
841 lineNumber = lastLineStart = characterOffset = 0;
842 readBufferPos = 0;
843 nbytesread = 0;
844#if QT_CONFIG(textcodec)
845 codec = QTextCodec::codecForMib(mib: 106); // utf8
846 delete decoder;
847 decoder = nullptr;
848#endif
849 attributeStack.clear();
850 attributeStack.reserve(extraCapacity: 16);
851 entityParser.reset();
852 hasCheckedStartDocument = false;
853 normalizeLiterals = false;
854 hasSeenTag = false;
855 atEnd = false;
856 inParseEntity = false;
857 referenceToUnparsedEntityDetected = false;
858 referenceToParameterEntityDetected = false;
859 hasExternalDtdSubset = false;
860 lockEncoding = false;
861 namespaceProcessing = true;
862 rawReadBuffer.clear();
863 dataBuffer.clear();
864 readBuffer.clear();
865 tagStackStringStorageSize = initialTagStackStringStorageSize;
866
867 type = QXmlStreamReader::NoToken;
868 error = QXmlStreamReader::NoError;
869}
870
871/*
872 Well-formed requires that we verify entity values. We do this with a
873 standard parser.
874 */
875void QXmlStreamReaderPrivate::parseEntity(const QString &value)
876{
877 Q_Q(QXmlStreamReader);
878
879 if (value.isEmpty())
880 return;
881
882
883 if (!entityParser)
884 entityParser = qt_make_unique<QXmlStreamReaderPrivate>(args: q);
885 else
886 entityParser->init();
887 entityParser->inParseEntity = true;
888 entityParser->readBuffer = value;
889 entityParser->injectToken(tokenToInject: PARSE_ENTITY);
890 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
891 entityParser->parse();
892 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
893 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Invalid entity value."));
894
895}
896
897inline void QXmlStreamReaderPrivate::reallocateStack()
898{
899 stack_size <<= 1;
900 sym_stack = reinterpret_cast<Value*> (realloc(ptr: sym_stack, size: stack_size * sizeof(Value)));
901 Q_CHECK_PTR(sym_stack);
902 state_stack = reinterpret_cast<int*> (realloc(ptr: state_stack, size: stack_size * sizeof(int)));
903 Q_CHECK_PTR(state_stack);
904}
905
906
907QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
908{
909#if QT_CONFIG(textcodec)
910 delete decoder;
911#endif
912 free(ptr: sym_stack);
913 free(ptr: state_stack);
914}
915
916
917inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
918{
919 uint peekc = peekChar();
920 if (peekc == '\n') {
921 if (putStack.size())
922 putStack.pop();
923 else
924 ++readBufferPos;
925 return peekc;
926 }
927 if (peekc == StreamEOF) {
928 putChar(c: '\r');
929 return 0;
930 }
931 return '\n';
932}
933
934/*!
935 \internal
936 If the end of the file is encountered, ~0 is returned.
937 */
938inline uint QXmlStreamReaderPrivate::getChar()
939{
940 uint c;
941 if (putStack.size()) {
942 c = atEnd ? StreamEOF : putStack.pop();
943 } else {
944 if (readBufferPos < readBuffer.size())
945 c = readBuffer.at(i: readBufferPos++).unicode();
946 else
947 c = getChar_helper();
948 }
949
950 return c;
951}
952
953inline uint QXmlStreamReaderPrivate::peekChar()
954{
955 uint c;
956 if (putStack.size()) {
957 c = putStack.top();
958 } else if (readBufferPos < readBuffer.size()) {
959 c = readBuffer.at(i: readBufferPos).unicode();
960 } else {
961 if ((c = getChar_helper()) != StreamEOF)
962 --readBufferPos;
963 }
964
965 return c;
966}
967
968/*!
969 \internal
970
971 Scans characters until \a str is encountered, and validates the characters
972 as according to the Char[2] production and do the line-ending normalization.
973 If any character is invalid, false is returned, otherwise true upon success.
974
975 If \a tokenToInject is not less than zero, injectToken() is called with
976 \a tokenToInject when \a str is found.
977
978 If any error occurred, false is returned, otherwise true.
979 */
980bool QXmlStreamReaderPrivate::scanUntil(const char *str, short tokenToInject)
981{
982 int pos = textBuffer.size();
983 int oldLineNumber = lineNumber;
984
985 uint c;
986 while ((c = getChar()) != StreamEOF) {
987 /* First, we do the validation & normalization. */
988 switch (c) {
989 case '\r':
990 if ((c = filterCarriageReturn()) == 0)
991 break;
992 Q_FALLTHROUGH();
993 case '\n':
994 ++lineNumber;
995 lastLineStart = characterOffset + readBufferPos;
996 Q_FALLTHROUGH();
997 case '\t':
998 textBuffer += QChar(c);
999 continue;
1000 default:
1001 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1002 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Invalid XML character."));
1003 lineNumber = oldLineNumber;
1004 return false;
1005 }
1006 textBuffer += QChar(c);
1007 }
1008
1009
1010 /* Second, attempt to lookup str. */
1011 if (c == uint(*str)) {
1012 if (!*(str + 1)) {
1013 if (tokenToInject >= 0)
1014 injectToken(tokenToInject);
1015 return true;
1016 } else {
1017 if (scanString(str: str + 1, tokenToInject, requireSpace: false))
1018 return true;
1019 }
1020 }
1021 }
1022 putString(s: textBuffer, from: pos);
1023 textBuffer.resize(size: pos);
1024 lineNumber = oldLineNumber;
1025 return false;
1026}
1027
1028bool QXmlStreamReaderPrivate::scanString(const char *str, short tokenToInject, bool requireSpace)
1029{
1030 int n = 0;
1031 while (str[n]) {
1032 uint c = getChar();
1033 if (c != ushort(str[n])) {
1034 if (c != StreamEOF)
1035 putChar(c);
1036 while (n--) {
1037 putChar(c: ushort(str[n]));
1038 }
1039 return false;
1040 }
1041 ++n;
1042 }
1043 for (int i = 0; i < n; ++i)
1044 textBuffer += QChar(ushort(str[i]));
1045 if (requireSpace) {
1046 int s = fastScanSpace();
1047 if (!s || atEnd) {
1048 int pos = textBuffer.size() - n - s;
1049 putString(s: textBuffer, from: pos);
1050 textBuffer.resize(size: pos);
1051 return false;
1052 }
1053 }
1054 if (tokenToInject >= 0)
1055 injectToken(tokenToInject);
1056 return true;
1057}
1058
1059bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1060{
1061 switch (peekChar()) {
1062 case '[':
1063 return scanString(str: spell[CDATA_START], tokenToInject: CDATA_START, requireSpace: false);
1064 case 'D':
1065 return scanString(str: spell[DOCTYPE], tokenToInject: DOCTYPE);
1066 case 'A':
1067 return scanString(str: spell[ATTLIST], tokenToInject: ATTLIST);
1068 case 'N':
1069 return scanString(str: spell[NOTATION], tokenToInject: NOTATION);
1070 case 'E':
1071 if (scanString(str: spell[ELEMENT], tokenToInject: ELEMENT))
1072 return true;
1073 return scanString(str: spell[ENTITY], tokenToInject: ENTITY);
1074
1075 default:
1076 ;
1077 };
1078 return false;
1079}
1080
1081bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1082{
1083 switch (peekChar()) {
1084 case 'S':
1085 return scanString(str: spell[SYSTEM], tokenToInject: SYSTEM);
1086 case 'P':
1087 return scanString(str: spell[PUBLIC], tokenToInject: PUBLIC);
1088 default:
1089 ;
1090 }
1091 return false;
1092}
1093
1094bool QXmlStreamReaderPrivate::scanNData()
1095{
1096 if (fastScanSpace()) {
1097 if (scanString(str: spell[NDATA], tokenToInject: NDATA))
1098 return true;
1099 putChar(c: ' ');
1100 }
1101 return false;
1102}
1103
1104bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1105{
1106 switch (peekChar()) {
1107 case 'R':
1108 return scanString(str: spell[REQUIRED], tokenToInject: REQUIRED, requireSpace: false);
1109 case 'I':
1110 return scanString(str: spell[IMPLIED], tokenToInject: IMPLIED, requireSpace: false);
1111 case 'F':
1112 return scanString(str: spell[FIXED], tokenToInject: FIXED, requireSpace: false);
1113 default:
1114 ;
1115 }
1116 return false;
1117}
1118
1119bool QXmlStreamReaderPrivate::scanAttType()
1120{
1121 switch (peekChar()) {
1122 case 'C':
1123 return scanString(str: spell[CDATA], tokenToInject: CDATA);
1124 case 'I':
1125 if (scanString(str: spell[ID], tokenToInject: ID))
1126 return true;
1127 if (scanString(str: spell[IDREF], tokenToInject: IDREF))
1128 return true;
1129 return scanString(str: spell[IDREFS], tokenToInject: IDREFS);
1130 case 'E':
1131 if (scanString(str: spell[ENTITY], tokenToInject: ENTITY))
1132 return true;
1133 return scanString(str: spell[ENTITIES], tokenToInject: ENTITIES);
1134 case 'N':
1135 if (scanString(str: spell[NOTATION], tokenToInject: NOTATION))
1136 return true;
1137 if (scanString(str: spell[NMTOKEN], tokenToInject: NMTOKEN))
1138 return true;
1139 return scanString(str: spell[NMTOKENS], tokenToInject: NMTOKENS);
1140 default:
1141 ;
1142 }
1143 return false;
1144}
1145
1146/*!
1147 \internal
1148
1149 Scan strings with quotes or apostrophes surround them. For instance,
1150 attributes, the version and encoding field in the XML prolog and
1151 entity declarations.
1152
1153 If normalizeLiterals is set to true, the function also normalizes
1154 whitespace. It is set to true when the first start tag is
1155 encountered.
1156
1157 */
1158inline int QXmlStreamReaderPrivate::fastScanLiteralContent()
1159{
1160 int n = 0;
1161 uint c;
1162 while ((c = getChar()) != StreamEOF) {
1163 switch (ushort(c)) {
1164 case 0xfffe:
1165 case 0xffff:
1166 case 0:
1167 /* The putChar() call is necessary so the parser re-gets
1168 * the character from the input source, when raising an error. */
1169 putChar(c);
1170 return n;
1171 case '\r':
1172 if (filterCarriageReturn() == 0)
1173 return n;
1174 Q_FALLTHROUGH();
1175 case '\n':
1176 ++lineNumber;
1177 lastLineStart = characterOffset + readBufferPos;
1178 Q_FALLTHROUGH();
1179 case ' ':
1180 case '\t':
1181 if (normalizeLiterals)
1182 textBuffer += QLatin1Char(' ');
1183 else
1184 textBuffer += QChar(c);
1185 ++n;
1186 break;
1187 case '&':
1188 case '<':
1189 case '\"':
1190 case '\'':
1191 if (!(c & 0xff0000)) {
1192 putChar(c);
1193 return n;
1194 }
1195 Q_FALLTHROUGH();
1196 default:
1197 if (c < 0x20) {
1198 putChar(c);
1199 return n;
1200 }
1201 textBuffer += QChar(c);
1202 ++n;
1203 }
1204 }
1205 return n;
1206}
1207
1208inline int QXmlStreamReaderPrivate::fastScanSpace()
1209{
1210 int n = 0;
1211 uint c;
1212 while ((c = getChar()) != StreamEOF) {
1213 switch (c) {
1214 case '\r':
1215 if ((c = filterCarriageReturn()) == 0)
1216 return n;
1217 Q_FALLTHROUGH();
1218 case '\n':
1219 ++lineNumber;
1220 lastLineStart = characterOffset + readBufferPos;
1221 Q_FALLTHROUGH();
1222 case ' ':
1223 case '\t':
1224 textBuffer += QChar(c);
1225 ++n;
1226 break;
1227 default:
1228 putChar(c);
1229 return n;
1230 }
1231 }
1232 return n;
1233}
1234
1235/*!
1236 \internal
1237
1238 Used for text nodes essentially. That is, characters appearing
1239 inside elements.
1240 */
1241inline int QXmlStreamReaderPrivate::fastScanContentCharList()
1242{
1243 int n = 0;
1244 uint c;
1245 while ((c = getChar()) != StreamEOF) {
1246 switch (ushort(c)) {
1247 case 0xfffe:
1248 case 0xffff:
1249 case 0:
1250 putChar(c);
1251 return n;
1252 case ']': {
1253 isWhitespace = false;
1254 int pos = textBuffer.size();
1255 textBuffer += QChar(ushort(c));
1256 ++n;
1257 while ((c = getChar()) == ']') {
1258 textBuffer += QChar(ushort(c));
1259 ++n;
1260 }
1261 if (c == 0) {
1262 putString(s: textBuffer, from: pos);
1263 textBuffer.resize(size: pos);
1264 } else if (c == '>' && textBuffer.at(i: textBuffer.size()-2) == QLatin1Char(']')) {
1265 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Sequence ']]>' not allowed in content."));
1266 } else {
1267 putChar(c);
1268 break;
1269 }
1270 return n;
1271 } break;
1272 case '\r':
1273 if ((c = filterCarriageReturn()) == 0)
1274 return n;
1275 Q_FALLTHROUGH();
1276 case '\n':
1277 ++lineNumber;
1278 lastLineStart = characterOffset + readBufferPos;
1279 Q_FALLTHROUGH();
1280 case ' ':
1281 case '\t':
1282 textBuffer += QChar(ushort(c));
1283 ++n;
1284 break;
1285 case '&':
1286 case '<':
1287 if (!(c & 0xff0000)) {
1288 putChar(c);
1289 return n;
1290 }
1291 Q_FALLTHROUGH();
1292 default:
1293 if (c < 0x20) {
1294 putChar(c);
1295 return n;
1296 }
1297 isWhitespace = false;
1298 textBuffer += QChar(ushort(c));
1299 ++n;
1300 }
1301 }
1302 return n;
1303}
1304
1305inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
1306{
1307 int n = 0;
1308 uint c;
1309 while ((c = getChar()) != StreamEOF) {
1310 if (n >= 4096) {
1311 // This is too long to be a sensible name, and
1312 // can exhaust memory
1313 return 0;
1314 }
1315 switch (c) {
1316 case '\n':
1317 case ' ':
1318 case '\t':
1319 case '\r':
1320 case '&':
1321 case '#':
1322 case '\'':
1323 case '\"':
1324 case '<':
1325 case '>':
1326 case '[':
1327 case ']':
1328 case '=':
1329 case '%':
1330 case '/':
1331 case ';':
1332 case '?':
1333 case '!':
1334 case '^':
1335 case '|':
1336 case ',':
1337 case '(':
1338 case ')':
1339 case '+':
1340 case '*':
1341 putChar(c);
1342 if (prefix && *prefix == n+1) {
1343 *prefix = 0;
1344 putChar(c: ':');
1345 --n;
1346 }
1347 return n;
1348 case ':':
1349 if (prefix) {
1350 if (*prefix == 0) {
1351 *prefix = n+2;
1352 } else { // only one colon allowed according to the namespace spec.
1353 putChar(c);
1354 return n;
1355 }
1356 } else {
1357 putChar(c);
1358 return n;
1359 }
1360 Q_FALLTHROUGH();
1361 default:
1362 textBuffer += QChar(c);
1363 ++n;
1364 }
1365 }
1366
1367 if (prefix)
1368 *prefix = 0;
1369 int pos = textBuffer.size() - n;
1370 putString(s: textBuffer, from: pos);
1371 textBuffer.resize(size: pos);
1372 return 0;
1373}
1374
1375enum NameChar { NameBeginning, NameNotBeginning, NotName };
1376
1377static const char Begi = static_cast<char>(NameBeginning);
1378static const char NtBg = static_cast<char>(NameNotBeginning);
1379static const char NotN = static_cast<char>(NotName);
1380
1381static const char nameCharTable[128] =
1382{
1383// 0x00
1384 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1385 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1386// 0x10
1387 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1388 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1389// 0x20 (0x2D is '-', 0x2E is '.')
1390 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1391 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1392// 0x30 (0x30..0x39 are '0'..'9', 0x3A is ':')
1393 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1394 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1395// 0x40 (0x41..0x5A are 'A'..'Z')
1396 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1397 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1398// 0x50 (0x5F is '_')
1399 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1400 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1401// 0x60 (0x61..0x7A are 'a'..'z')
1402 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1403 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1404// 0x70
1405 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1406 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1407};
1408
1409static inline NameChar fastDetermineNameChar(QChar ch)
1410{
1411 ushort uc = ch.unicode();
1412 if (!(uc & ~0x7f)) // uc < 128
1413 return static_cast<NameChar>(nameCharTable[uc]);
1414
1415 QChar::Category cat = ch.category();
1416 // ### some these categories might be slightly wrong
1417 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1418 || cat == QChar::Number_Letter)
1419 return NameBeginning;
1420 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1421 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1422 return NameNotBeginning;
1423 return NotName;
1424}
1425
1426inline int QXmlStreamReaderPrivate::fastScanNMTOKEN()
1427{
1428 int n = 0;
1429 uint c;
1430 while ((c = getChar()) != StreamEOF) {
1431 if (fastDetermineNameChar(ch: QChar(c)) == NotName) {
1432 putChar(c);
1433 return n;
1434 } else {
1435 ++n;
1436 textBuffer += QChar(c);
1437 }
1438 }
1439
1440 int pos = textBuffer.size() - n;
1441 putString(s: textBuffer, from: pos);
1442 textBuffer.resize(size: pos);
1443
1444 return n;
1445}
1446
1447void QXmlStreamReaderPrivate::putString(const QString &s, int from)
1448{
1449 putStack.reserve(extraCapacity: s.size());
1450 for (int i = s.size()-1; i >= from; --i)
1451 putStack.rawPush() = s.at(i).unicode();
1452}
1453
1454void QXmlStreamReaderPrivate::putStringLiteral(const QString &s)
1455{
1456 putStack.reserve(extraCapacity: s.size());
1457 for (int i = s.size()-1; i >= 0; --i)
1458 putStack.rawPush() = ((LETTER << 16) | s.at(i).unicode());
1459}
1460
1461void QXmlStreamReaderPrivate::putReplacement(const QString &s)
1462{
1463 putStack.reserve(extraCapacity: s.size());
1464 for (int i = s.size()-1; i >= 0; --i) {
1465 ushort c = s.at(i).unicode();
1466 if (c == '\n' || c == '\r')
1467 putStack.rawPush() = ((LETTER << 16) | c);
1468 else
1469 putStack.rawPush() = c;
1470 }
1471}
1472void QXmlStreamReaderPrivate::putReplacementInAttributeValue(const QString &s)
1473{
1474 putStack.reserve(extraCapacity: s.size());
1475 for (int i = s.size()-1; i >= 0; --i) {
1476 ushort c = s.at(i).unicode();
1477 if (c == '&' || c == ';')
1478 putStack.rawPush() = c;
1479 else if (c == '\n' || c == '\r')
1480 putStack.rawPush() = ' ';
1481 else
1482 putStack.rawPush() = ((LETTER << 16) | c);
1483 }
1484}
1485
1486uint QXmlStreamReaderPrivate::getChar_helper()
1487{
1488 const int BUFFER_SIZE = 8192;
1489 characterOffset += readBufferPos;
1490 readBufferPos = 0;
1491 if (readBuffer.size())
1492 readBuffer.resize(size: 0);
1493#if QT_CONFIG(textcodec)
1494 if (decoder)
1495#endif
1496 nbytesread = 0;
1497 if (device) {
1498 rawReadBuffer.resize(size: BUFFER_SIZE);
1499 qint64 nbytesreadOrMinus1 = device->read(data: rawReadBuffer.data() + nbytesread, maxlen: BUFFER_SIZE - nbytesread);
1500 nbytesread += qMax(a: nbytesreadOrMinus1, b: qint64{0});
1501 } else {
1502 if (nbytesread)
1503 rawReadBuffer += dataBuffer;
1504 else
1505 rawReadBuffer = dataBuffer;
1506 nbytesread = rawReadBuffer.size();
1507 dataBuffer.clear();
1508 }
1509 if (!nbytesread) {
1510 atEnd = true;
1511 return StreamEOF;
1512 }
1513
1514#if QT_CONFIG(textcodec)
1515 if (!decoder) {
1516 if (nbytesread < 4) { // the 4 is to cover 0xef 0xbb 0xbf plus
1517 // one extra for the utf8 codec
1518 atEnd = true;
1519 return StreamEOF;
1520 }
1521 int mib = 106; // UTF-8
1522
1523 // look for byte order mark
1524 uchar ch1 = rawReadBuffer.at(i: 0);
1525 uchar ch2 = rawReadBuffer.at(i: 1);
1526 uchar ch3 = rawReadBuffer.at(i: 2);
1527 uchar ch4 = rawReadBuffer.at(i: 3);
1528
1529 if ((ch1 == 0 && ch2 == 0 && ch3 == 0xfe && ch4 == 0xff) ||
1530 (ch1 == 0xff && ch2 == 0xfe && ch3 == 0 && ch4 == 0))
1531 mib = 1017; // UTF-32 with byte order mark
1532 else if (ch1 == 0x3c && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x00)
1533 mib = 1019; // UTF-32LE
1534 else if (ch1 == 0x00 && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x3c)
1535 mib = 1018; // UTF-32BE
1536 else if ((ch1 == 0xfe && ch2 == 0xff) || (ch1 == 0xff && ch2 == 0xfe))
1537 mib = 1015; // UTF-16 with byte order mark
1538 else if (ch1 == 0x3c && ch2 == 0x00)
1539 mib = 1014; // UTF-16LE
1540 else if (ch1 == 0x00 && ch2 == 0x3c)
1541 mib = 1013; // UTF-16BE
1542 codec = QTextCodec::codecForMib(mib);
1543 Q_ASSERT(codec);
1544 decoder = codec->makeDecoder();
1545 }
1546
1547 decoder->toUnicode(target: &readBuffer, chars: rawReadBuffer.constData(), len: nbytesread);
1548
1549 if(lockEncoding && decoder->hasFailure()) {
1550 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Encountered incorrectly encoded content."));
1551 readBuffer.clear();
1552 return StreamEOF;
1553 }
1554#else
1555 readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread);
1556#endif // textcodec
1557
1558 readBuffer.reserve(asize: 1); // keep capacity when calling resize() next time
1559
1560 if (readBufferPos < readBuffer.size()) {
1561 ushort c = readBuffer.at(i: readBufferPos++).unicode();
1562 return c;
1563 }
1564
1565 atEnd = true;
1566 return StreamEOF;
1567}
1568
1569QStringRef QXmlStreamReaderPrivate::namespaceForPrefix(const QStringRef &prefix)
1570{
1571 for (int j = namespaceDeclarations.size() - 1; j >= 0; --j) {
1572 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(index: j);
1573 if (namespaceDeclaration.prefix == prefix) {
1574 return namespaceDeclaration.namespaceUri;
1575 }
1576 }
1577
1578#if 1
1579 if (namespaceProcessing && !prefix.isEmpty())
1580 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Namespace prefix '%1' not declared").arg(a: prefix));
1581#endif
1582
1583 return QStringRef();
1584}
1585
1586/*
1587 uses namespaceForPrefix and builds the attribute vector
1588 */
1589void QXmlStreamReaderPrivate::resolveTag()
1590{
1591 const auto attributeStackCleaner = qScopeGuard(f: [this](){ attributeStack.clear(); });
1592 int n = attributeStack.size();
1593
1594 if (namespaceProcessing) {
1595 for (int a = 0; a < dtdAttributes.size(); ++a) {
1596 DtdAttribute &dtdAttribute = dtdAttributes[a];
1597 if (!dtdAttribute.isNamespaceAttribute
1598 || dtdAttribute.defaultValue.isNull()
1599 || dtdAttribute.tagName != qualifiedName
1600 || dtdAttribute.attributeQualifiedName.isNull())
1601 continue;
1602 int i = 0;
1603 while (i < n && symName(symbol: attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1604 ++i;
1605 if (i != n)
1606 continue;
1607 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName == QLatin1String("xmlns")) {
1608 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1609 namespaceDeclaration.prefix.clear();
1610
1611 const QStringRef ns(dtdAttribute.defaultValue);
1612 if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") ||
1613 ns == QLatin1String("http://www.w3.org/XML/1998/namespace"))
1614 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Illegal namespace declaration."));
1615 else
1616 namespaceDeclaration.namespaceUri = ns;
1617 } else if (dtdAttribute.attributePrefix == QLatin1String("xmlns")) {
1618 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1619 QStringRef namespacePrefix = dtdAttribute.attributeName;
1620 QStringRef namespaceUri = dtdAttribute.defaultValue;
1621 if (((namespacePrefix == QLatin1String("xml"))
1622 ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
1623 || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
1624 || namespaceUri.isEmpty()
1625 || namespacePrefix == QLatin1String("xmlns"))
1626 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Illegal namespace declaration."));
1627
1628 namespaceDeclaration.prefix = namespacePrefix;
1629 namespaceDeclaration.namespaceUri = namespaceUri;
1630 }
1631 }
1632 }
1633
1634 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1635
1636 attributes.resize(asize: n);
1637
1638 for (int i = 0; i < n; ++i) {
1639 QXmlStreamAttribute &attribute = attributes[i];
1640 Attribute &attrib = attributeStack[i];
1641 QStringRef prefix(symPrefix(symbol: attrib.key));
1642 QStringRef name(symString(symbol: attrib.key));
1643 QStringRef qualifiedName(symName(symbol: attrib.key));
1644 QStringRef value(symString(symbol: attrib.value));
1645
1646 attribute.m_name = QXmlStreamStringRef(name);
1647 attribute.m_qualifiedName = QXmlStreamStringRef(qualifiedName);
1648 attribute.m_value = QXmlStreamStringRef(value);
1649
1650 if (!prefix.isEmpty()) {
1651 QStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1652 attribute.m_namespaceUri = QXmlStreamStringRef(attributeNamespaceUri);
1653 }
1654
1655 for (int j = 0; j < i; ++j) {
1656 if (attributes[j].name() == attribute.name()
1657 && attributes[j].namespaceUri() == attribute.namespaceUri()
1658 && (namespaceProcessing || attributes[j].qualifiedName() == attribute.qualifiedName()))
1659 {
1660 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Attribute '%1' redefined.").arg(a: attribute.qualifiedName()));
1661 return;
1662 }
1663 }
1664 }
1665
1666 for (int a = 0; a < dtdAttributes.size(); ++a) {
1667 DtdAttribute &dtdAttribute = dtdAttributes[a];
1668 if (dtdAttribute.isNamespaceAttribute
1669 || dtdAttribute.defaultValue.isNull()
1670 || dtdAttribute.tagName != qualifiedName
1671 || dtdAttribute.attributeQualifiedName.isNull())
1672 continue;
1673 int i = 0;
1674 while (i < n && symName(symbol: attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1675 ++i;
1676 if (i != n)
1677 continue;
1678
1679
1680
1681 QXmlStreamAttribute attribute;
1682 attribute.m_name = QXmlStreamStringRef(dtdAttribute.attributeName);
1683 attribute.m_qualifiedName = QXmlStreamStringRef(dtdAttribute.attributeQualifiedName);
1684 attribute.m_value = QXmlStreamStringRef(dtdAttribute.defaultValue);
1685
1686 if (!dtdAttribute.attributePrefix.isEmpty()) {
1687 QStringRef attributeNamespaceUri = namespaceForPrefix(prefix: dtdAttribute.attributePrefix);
1688 attribute.m_namespaceUri = QXmlStreamStringRef(attributeNamespaceUri);
1689 }
1690 attribute.m_isDefault = true;
1691 attributes.append(t: attribute);
1692 }
1693}
1694
1695void QXmlStreamReaderPrivate::resolvePublicNamespaces()
1696{
1697 const Tag &tag = tagStack.top();
1698 int n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
1699 publicNamespaceDeclarations.resize(asize: n);
1700 for (int i = 0; i < n; ++i) {
1701 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(index: tag.namespaceDeclarationsSize + i);
1702 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
1703 publicNamespaceDeclaration.m_prefix = QXmlStreamStringRef(namespaceDeclaration.prefix);
1704 publicNamespaceDeclaration.m_namespaceUri = QXmlStreamStringRef(namespaceDeclaration.namespaceUri);
1705 }
1706}
1707
1708void QXmlStreamReaderPrivate::resolveDtd()
1709{
1710 publicNotationDeclarations.resize(asize: notationDeclarations.size());
1711 for (int i = 0; i < notationDeclarations.size(); ++i) {
1712 const QXmlStreamReaderPrivate::NotationDeclaration &notationDeclaration = notationDeclarations.at(index: i);
1713 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
1714 publicNotationDeclaration.m_name = QXmlStreamStringRef(notationDeclaration.name);
1715 publicNotationDeclaration.m_systemId = QXmlStreamStringRef(notationDeclaration.systemId);
1716 publicNotationDeclaration.m_publicId = QXmlStreamStringRef(notationDeclaration.publicId);
1717
1718 }
1719 notationDeclarations.clear();
1720 publicEntityDeclarations.resize(asize: entityDeclarations.size());
1721 for (int i = 0; i < entityDeclarations.size(); ++i) {
1722 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(index: i);
1723 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
1724 publicEntityDeclaration.m_name = QXmlStreamStringRef(entityDeclaration.name);
1725 publicEntityDeclaration.m_notationName = QXmlStreamStringRef(entityDeclaration.notationName);
1726 publicEntityDeclaration.m_systemId = QXmlStreamStringRef(entityDeclaration.systemId);
1727 publicEntityDeclaration.m_publicId = QXmlStreamStringRef(entityDeclaration.publicId);
1728 publicEntityDeclaration.m_value = QXmlStreamStringRef(entityDeclaration.value);
1729 }
1730 entityDeclarations.clear();
1731 parameterEntityHash.clear();
1732}
1733
1734uint QXmlStreamReaderPrivate::resolveCharRef(int symbolIndex)
1735{
1736 bool ok = true;
1737 uint s;
1738 // ### add toXShort to QStringRef?
1739 if (sym(index: symbolIndex).c == 'x')
1740 s = symString(index: symbolIndex, offset: 1).toUInt(ok: &ok, base: 16);
1741 else
1742 s = symString(index: symbolIndex).toUInt(ok: &ok, base: 10);
1743
1744 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
1745 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
1746
1747 return ok ? s : 0;
1748}
1749
1750
1751void QXmlStreamReaderPrivate::checkPublicLiteral(const QStringRef &publicId)
1752{
1753//#x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
1754
1755 const ushort *data = reinterpret_cast<const ushort *>(publicId.constData());
1756 uchar c = 0;
1757 int i;
1758 for (i = publicId.size() - 1; i >= 0; --i) {
1759 if (data[i] < 256)
1760 switch ((c = data[i])) {
1761 case ' ': case '\n': case '\r': case '-': case '(': case ')':
1762 case '+': case ',': case '.': case '/': case ':': case '=':
1763 case '?': case ';': case '!': case '*': case '#': case '@':
1764 case '$': case '_': case '%': case '\'': case '\"':
1765 continue;
1766 default:
1767 if ((c >= 'a' && c <= 'z')
1768 || (c >= 'A' && c <= 'Z')
1769 || (c >= '0' && c <= '9'))
1770 continue;
1771 }
1772 break;
1773 }
1774 if (i >= 0)
1775 raiseWellFormedError(message: QXmlStream::tr(sourceText: "Unexpected character '%1' in public id literal.").arg(a: QChar(QLatin1Char(c))));
1776}
1777
1778/*
1779 Checks whether the document starts with an xml declaration. If it
1780 does, this function returns \c true; otherwise it sets up everything
1781 for a synthetic start document event and returns \c false.
1782 */
1783bool QXmlStreamReaderPrivate::checkStartDocument()
1784{
1785 hasCheckedStartDocument = true;
1786
1787 if (scanString(str: spell[XML], tokenToInject: XML))
1788 return true;
1789
1790 type = QXmlStreamReader::StartDocument;
1791 if (atEnd) {
1792 hasCheckedStartDocument = false;
1793 raiseError(error: QXmlStreamReader::PrematureEndOfDocumentError);
1794 }
1795 return false;
1796}
1797
1798void QXmlStreamReaderPrivate::startDocument()
1799{
1800 QString err;
1801 if (documentVersion != QLatin1String("1.0")) {
1802 if (documentVersion.contains(c: QLatin1Char(' ')))
1803 err = QXmlStream::tr(sourceText: "Invalid XML version string.");
1804 else
1805 err = QXmlStream::tr(sourceText: "Unsupported XML version.");
1806 }
1807 int n = attributeStack.size();
1808
1809 /* We use this bool to ensure that the pesudo attributes are in the
1810 * proper order:
1811 *
1812 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
1813 bool hasStandalone = false;
1814
1815 for (int i = 0; err.isNull() && i < n; ++i) {
1816 Attribute &attrib = attributeStack[i];
1817 QStringRef prefix(symPrefix(symbol: attrib.key));
1818 QStringRef key(symString(symbol: attrib.key));
1819 QStringRef value(symString(symbol: attrib.value));
1820
1821 if (prefix.isEmpty() && key == QLatin1String("encoding")) {
1822 documentEncoding = value;
1823
1824 if(hasStandalone)
1825 err = QXmlStream::tr(sourceText: "The standalone pseudo attribute must appear after the encoding.");
1826 if (!QXmlUtils::isEncName(encName: value))
1827 err = QXmlStream::tr(sourceText: "%1 is an invalid encoding name.").arg(a: value);
1828 else {
1829#if !QT_CONFIG(textcodec)
1830 readBuffer = QString::fromLatin1(rawReadBuffer.data(), nbytesread);
1831#else
1832 QTextCodec *const newCodec = QTextCodec::codecForName(name: value.toLatin1());
1833 if (!newCodec)
1834 err = QXmlStream::tr(sourceText: "Encoding %1 is unsupported").arg(a: value);
1835 else if (newCodec != codec && !lockEncoding) {
1836 codec = newCodec;
1837 delete decoder;
1838 decoder = codec->makeDecoder();
1839 decoder->toUnicode(target: &readBuffer, chars: rawReadBuffer.data(), len: nbytesread);
1840 }
1841#endif // textcodec
1842 }
1843 } else if (prefix.isEmpty() && key == QLatin1String("standalone")) {
1844 hasStandalone = true;
1845 if (value == QLatin1String("yes"))
1846 standalone = true;
1847 else if (value == QLatin1String("no"))
1848 standalone = false;
1849 else
1850 err = QXmlStream::tr(sourceText: "Standalone accepts only yes or no.");
1851 } else {
1852 err = QXmlStream::tr(sourceText: "Invalid attribute in XML declaration.");
1853 }
1854 }
1855
1856 if (!err.isNull())
1857 raiseWellFormedError(message: err);
1858 attributeStack.clear();
1859}
1860
1861
1862void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error, const QString& message)
1863{
1864 this->error = error;
1865 errorString = message;
1866 if (errorString.isNull()) {
1867 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
1868 errorString = QXmlStream::tr(sourceText: "Premature end of document.");
1869 else if (error == QXmlStreamReader::CustomError)
1870 errorString = QXmlStream::tr(sourceText: "Invalid document.");
1871 }
1872
1873 type = QXmlStreamReader::Invalid;
1874}
1875
1876void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
1877{
1878 raiseError(error: QXmlStreamReader::NotWellFormedError, message);
1879}
1880
1881void QXmlStreamReaderPrivate::parseError()
1882{
1883
1884 if (token == EOF_SYMBOL) {
1885 raiseError(error: QXmlStreamReader::PrematureEndOfDocumentError);
1886 return;
1887 }
1888 const int nmax = 4;
1889 QString error_message;
1890 int ers = state_stack[tos];
1891 int nexpected = 0;
1892 int expected[nmax];
1893 if (token != ERROR)
1894 for (int tk = 0; tk < TERMINAL_COUNT; ++tk) {
1895 int k = t_action(state: ers, token: tk);
1896 if (k <= 0)
1897 continue;
1898 if (spell[tk]) {
1899 if (nexpected < nmax)
1900 expected[nexpected++] = tk;
1901 }
1902 }
1903
1904 if (nexpected && nexpected < nmax) {
1905 //: '<first option>'
1906 QString exp_str = QXmlStream::tr(sourceText: "'%1'", disambiguation: "expected").arg(a: QLatin1String(spell[expected[0]]));
1907 if (nexpected == 2) {
1908 //: <first option>, '<second option>'
1909 exp_str = QXmlStream::tr(sourceText: "%1 or '%2'", disambiguation: "expected").arg(args&: exp_str, args: QLatin1String(spell[expected[1]]));
1910 } else if (nexpected > 2) {
1911 int s = 1;
1912 for (; s < nexpected - 1; ++s) {
1913 //: <options so far>, '<next option>'
1914 exp_str = QXmlStream::tr(sourceText: "%1, '%2'", disambiguation: "expected").arg(args&: exp_str, args: QLatin1String(spell[expected[s]]));
1915 }
1916 //: <options so far>, or '<final option>'
1917 exp_str = QXmlStream::tr(sourceText: "%1, or '%2'", disambiguation: "expected").arg(args&: exp_str, args: QLatin1String(spell[expected[s]]));
1918 }
1919 error_message = QXmlStream::tr(sourceText: "Expected %1, but got '%2'.").arg(args&: exp_str, args: QLatin1String(spell[token]));
1920 } else {
1921 error_message = QXmlStream::tr(sourceText: "Unexpected '%1'.").arg(a: QLatin1String(spell[token]));
1922 }
1923
1924 raiseWellFormedError(message: error_message);
1925}
1926
1927void QXmlStreamReaderPrivate::resume(int rule) {
1928 resumeReduction = rule;
1929 if (error == QXmlStreamReader::NoError)
1930 raiseError(error: QXmlStreamReader::PrematureEndOfDocumentError);
1931}
1932
1933/*! Returns the current line number, starting with 1.
1934
1935\sa columnNumber(), characterOffset()
1936 */
1937qint64 QXmlStreamReader::lineNumber() const
1938{
1939 Q_D(const QXmlStreamReader);
1940 return d->lineNumber + 1; // in public we start with 1
1941}
1942
1943/*! Returns the current column number, starting with 0.
1944
1945\sa lineNumber(), characterOffset()
1946 */
1947qint64 QXmlStreamReader::columnNumber() const
1948{
1949 Q_D(const QXmlStreamReader);
1950 return d->characterOffset - d->lastLineStart + d->readBufferPos;
1951}
1952
1953/*! Returns the current character offset, starting with 0.
1954
1955\sa lineNumber(), columnNumber()
1956*/
1957qint64 QXmlStreamReader::characterOffset() const
1958{
1959 Q_D(const QXmlStreamReader);
1960 return d->characterOffset + d->readBufferPos;
1961}
1962
1963
1964/*! Returns the text of \l Characters, \l Comment, \l DTD, or
1965 EntityReference.
1966 */
1967QStringRef QXmlStreamReader::text() const
1968{
1969 Q_D(const QXmlStreamReader);
1970 return d->text;
1971}
1972
1973
1974/*! If the tokenType() is \l DTD, this function returns the DTD's
1975 notation declarations. Otherwise an empty vector is returned.
1976
1977 The QXmlStreamNotationDeclarations class is defined to be a QVector
1978 of QXmlStreamNotationDeclaration.
1979 */
1980QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations() const
1981{
1982 Q_D(const QXmlStreamReader);
1983 if (d->notationDeclarations.size())
1984 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
1985 return d->publicNotationDeclarations;
1986}
1987
1988
1989/*! If the tokenType() is \l DTD, this function returns the DTD's
1990 unparsed (external) entity declarations. Otherwise an empty vector is returned.
1991
1992 The QXmlStreamEntityDeclarations class is defined to be a QVector
1993 of QXmlStreamEntityDeclaration.
1994 */
1995QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations() const
1996{
1997 Q_D(const QXmlStreamReader);
1998 if (d->entityDeclarations.size())
1999 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2000 return d->publicEntityDeclarations;
2001}
2002
2003/*!
2004 \since 4.4
2005
2006 If the tokenType() is \l DTD, this function returns the DTD's
2007 name. Otherwise an empty string is returned.
2008
2009 */
2010QStringRef QXmlStreamReader::dtdName() const
2011{
2012 Q_D(const QXmlStreamReader);
2013 if (d->type == QXmlStreamReader::DTD)
2014 return d->dtdName;
2015 return QStringRef();
2016}
2017
2018/*!
2019 \since 4.4
2020
2021 If the tokenType() is \l DTD, this function returns the DTD's
2022 public identifier. Otherwise an empty string is returned.
2023
2024 */
2025QStringRef QXmlStreamReader::dtdPublicId() const
2026{
2027 Q_D(const QXmlStreamReader);
2028 if (d->type == QXmlStreamReader::DTD)
2029 return d->dtdPublicId;
2030 return QStringRef();
2031}
2032
2033/*!
2034 \since 4.4
2035
2036 If the tokenType() is \l DTD, this function returns the DTD's
2037 system identifier. Otherwise an empty string is returned.
2038
2039 */
2040QStringRef QXmlStreamReader::dtdSystemId() const
2041{
2042 Q_D(const QXmlStreamReader);
2043 if (d->type == QXmlStreamReader::DTD)
2044 return d->dtdSystemId;
2045 return QStringRef();
2046}
2047
2048/*!
2049 \since 5.15
2050
2051 Returns the maximum amount of characters a single entity is
2052 allowed to expand into. If a single entity expands past the
2053 given limit, the document is not considered well formed.
2054
2055 \sa setEntityExpansionLimit
2056*/
2057int QXmlStreamReader::entityExpansionLimit() const
2058{
2059 Q_D(const QXmlStreamReader);
2060 return d->entityExpansionLimit;
2061}
2062
2063/*!
2064 \since 5.15
2065
2066 Sets the maximum amount of characters a single entity is
2067 allowed to expand into to \a limit. If a single entity expands
2068 past the given limit, the document is not considered well formed.
2069
2070 The limit is there to prevent DoS attacks when loading unknown
2071 XML documents where recursive entity expansion could otherwise
2072 exhaust all available memory.
2073
2074 The default value for this property is 4096 characters.
2075
2076 \sa entityExpansionLimit
2077*/
2078void QXmlStreamReader::setEntityExpansionLimit(int limit)
2079{
2080 Q_D(QXmlStreamReader);
2081 d->entityExpansionLimit = limit;
2082}
2083
2084/*! If the tokenType() is \l StartElement, this function returns the
2085 element's namespace declarations. Otherwise an empty vector is
2086 returned.
2087
2088 The QXmlStreamNamespaceDeclarations class is defined to be a QVector
2089 of QXmlStreamNamespaceDeclaration.
2090
2091 \sa addExtraNamespaceDeclaration(), addExtraNamespaceDeclarations()
2092 */
2093QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations() const
2094{
2095 Q_D(const QXmlStreamReader);
2096 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2097 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2098 return d->publicNamespaceDeclarations;
2099}
2100
2101
2102/*!
2103 \since 4.4
2104
2105 Adds an \a extraNamespaceDeclaration. The declaration will be
2106 valid for children of the current element, or - should the function
2107 be called before any elements are read - for the entire XML
2108 document.
2109
2110 \sa namespaceDeclarations(), addExtraNamespaceDeclarations(), setNamespaceProcessing()
2111 */
2112void QXmlStreamReader::addExtraNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2113{
2114 Q_D(QXmlStreamReader);
2115 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2116 namespaceDeclaration.prefix = d->addToStringStorage(s: extraNamespaceDeclaration.prefix());
2117 namespaceDeclaration.namespaceUri = d->addToStringStorage(s: extraNamespaceDeclaration.namespaceUri());
2118}
2119
2120/*!
2121 \since 4.4
2122
2123 Adds a vector of declarations specified by \a extraNamespaceDeclarations.
2124
2125 \sa namespaceDeclarations(), addExtraNamespaceDeclaration()
2126 */
2127void QXmlStreamReader::addExtraNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2128{
2129 for (int i = 0; i < extraNamespaceDeclarations.size(); ++i)
2130 addExtraNamespaceDeclaration(extraNamespaceDeclaration: extraNamespaceDeclarations.at(i));
2131}
2132
2133
2134/*! Convenience function to be called in case a StartElement was
2135 read. Reads until the corresponding EndElement and returns all text
2136 in-between. In case of no error, the current token (see tokenType())
2137 after having called this function is EndElement.
2138
2139 The function concatenates text() when it reads either \l Characters
2140 or EntityReference tokens, but skips ProcessingInstruction and \l
2141 Comment. If the current token is not StartElement, an empty string is
2142 returned.
2143
2144 The \a behaviour defines what happens in case anything else is
2145 read before reaching EndElement. The function can include the text from
2146 child elements (useful for example for HTML), ignore child elements, or
2147 raise an UnexpectedElementError and return what was read so far (default).
2148
2149 \since 4.6
2150 */
2151QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2152{
2153 Q_D(QXmlStreamReader);
2154 if (isStartElement()) {
2155 QString result;
2156 forever {
2157 switch (readNext()) {
2158 case Characters:
2159 case EntityReference:
2160 result.insert(i: result.size(), uc: d->text.unicode(), len: d->text.size());
2161 break;
2162 case EndElement:
2163 return result;
2164 case ProcessingInstruction:
2165 case Comment:
2166 break;
2167 case StartElement:
2168 if (behaviour == SkipChildElements) {
2169 skipCurrentElement();
2170 break;
2171 } else if (behaviour == IncludeChildElements) {
2172 result += readElementText(behaviour);
2173 break;
2174 }
2175 Q_FALLTHROUGH();
2176 default:
2177 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2178 if (!d->error)
2179 d->raiseError(error: UnexpectedElementError, message: QXmlStream::tr(sourceText: "Expected character data."));
2180 return result;
2181 }
2182 }
2183 }
2184 }
2185 return QString();
2186}
2187
2188/*! Raises a custom error with an optional error \a message.
2189
2190 \sa error(), errorString()
2191 */
2192void QXmlStreamReader::raiseError(const QString& message)
2193{
2194 Q_D(QXmlStreamReader);
2195 d->raiseError(error: CustomError, message);
2196}
2197
2198/*!
2199 Returns the error message that was set with raiseError().
2200
2201 \sa error(), lineNumber(), columnNumber(), characterOffset()
2202 */
2203QString QXmlStreamReader::errorString() const
2204{
2205 Q_D(const QXmlStreamReader);
2206 if (d->type == QXmlStreamReader::Invalid)
2207 return d->errorString;
2208 return QString();
2209}
2210
2211/*! Returns the type of the current error, or NoError if no error occurred.
2212
2213 \sa errorString(), raiseError()
2214 */
2215QXmlStreamReader::Error QXmlStreamReader::error() const
2216{
2217 Q_D(const QXmlStreamReader);
2218 if (d->type == QXmlStreamReader::Invalid)
2219 return d->error;
2220 return NoError;
2221}
2222
2223/*!
2224 Returns the target of a ProcessingInstruction.
2225 */
2226QStringRef QXmlStreamReader::processingInstructionTarget() const
2227{
2228 Q_D(const QXmlStreamReader);
2229 return d->processingInstructionTarget;
2230}
2231
2232/*!
2233 Returns the data of a ProcessingInstruction.
2234 */
2235QStringRef QXmlStreamReader::processingInstructionData() const
2236{
2237 Q_D(const QXmlStreamReader);
2238 return d->processingInstructionData;
2239}
2240
2241
2242
2243/*!
2244 Returns the local name of a StartElement, EndElement, or an EntityReference.
2245
2246 \sa namespaceUri(), qualifiedName()
2247 */
2248QStringRef QXmlStreamReader::name() const
2249{
2250 Q_D(const QXmlStreamReader);
2251 return d->name;
2252}
2253
2254/*!
2255 Returns the namespaceUri of a StartElement or EndElement.
2256
2257 \sa name(), qualifiedName()
2258 */
2259QStringRef QXmlStreamReader::namespaceUri() const
2260{
2261 Q_D(const QXmlStreamReader);
2262 return d->namespaceUri;
2263}
2264
2265/*!
2266 Returns the qualified name of a StartElement or EndElement;
2267
2268 A qualified name is the raw name of an element in the XML data. It
2269 consists of the namespace prefix, followed by colon, followed by the
2270 element's local name. Since the namespace prefix is not unique (the
2271 same prefix can point to different namespaces and different prefixes
2272 can point to the same namespace), you shouldn't use qualifiedName(),
2273 but the resolved namespaceUri() and the attribute's local name().
2274
2275 \sa name(), prefix(), namespaceUri()
2276 */
2277QStringRef QXmlStreamReader::qualifiedName() const
2278{
2279 Q_D(const QXmlStreamReader);
2280 return d->qualifiedName;
2281}
2282
2283
2284
2285/*!
2286 \since 4.4
2287
2288 Returns the prefix of a StartElement or EndElement.
2289
2290 \sa name(), qualifiedName()
2291*/
2292QStringRef QXmlStreamReader::prefix() const
2293{
2294 Q_D(const QXmlStreamReader);
2295 return d->prefix;
2296}
2297
2298/*!
2299 Returns the attributes of a StartElement.
2300 */
2301QXmlStreamAttributes QXmlStreamReader::attributes() const
2302{
2303 Q_D(const QXmlStreamReader);
2304 return d->attributes;
2305}
2306
2307#endif // QT_NO_XMLSTREAMREADER
2308
2309/*!
2310 \class QXmlStreamAttribute
2311 \inmodule QtCore
2312 \since 4.3
2313 \reentrant
2314 \brief The QXmlStreamAttribute class represents a single XML attribute.
2315
2316 \ingroup xml-tools
2317
2318 An attribute consists of an optionally empty namespaceUri(), a
2319 name(), a value(), and an isDefault() attribute.
2320
2321 The raw XML attribute name is returned as qualifiedName().
2322*/
2323
2324/*!
2325 Creates an empty attribute.
2326 */
2327QXmlStreamAttribute::QXmlStreamAttribute()
2328{
2329 m_isDefault = false;
2330}
2331
2332#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2333/*!
2334 Destructs an attribute.
2335 */
2336QXmlStreamAttribute::~QXmlStreamAttribute()
2337{
2338}
2339#endif
2340
2341/*! Constructs an attribute in the namespace described with \a
2342 namespaceUri with \a name and value \a value.
2343 */
2344QXmlStreamAttribute::QXmlStreamAttribute(const QString &namespaceUri, const QString &name, const QString &value)
2345{
2346 m_namespaceUri = QXmlStreamStringRef(QStringRef(&namespaceUri));
2347 m_name = m_qualifiedName = QXmlStreamStringRef(QStringRef(&name));
2348 m_value = QXmlStreamStringRef(QStringRef(&value));
2349 m_namespaceUri = QXmlStreamStringRef(QStringRef(&namespaceUri));
2350}
2351
2352/*!
2353 Constructs an attribute with qualified name \a qualifiedName and value \a value.
2354 */
2355QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QString &value)
2356{
2357 int colon = qualifiedName.indexOf(c: QLatin1Char(':'));
2358 m_name = QXmlStreamStringRef(QStringRef(&qualifiedName,
2359 colon + 1,
2360 qualifiedName.size() - (colon + 1)));
2361 m_qualifiedName = QXmlStreamStringRef(QStringRef(&qualifiedName));
2362 m_value = QXmlStreamStringRef(QStringRef(&value));
2363}
2364
2365/*! \fn QStringRef QXmlStreamAttribute::namespaceUri() const
2366
2367 Returns the attribute's resolved namespaceUri, or an empty string
2368 reference if the attribute does not have a defined namespace.
2369 */
2370/*! \fn QStringRef QXmlStreamAttribute::name() const
2371 Returns the attribute's local name.
2372 */
2373/*! \fn QStringRef QXmlStreamAttribute::qualifiedName() const
2374 Returns the attribute's qualified name.
2375
2376 A qualified name is the raw name of an attribute in the XML
2377 data. It consists of the namespace prefix(), followed by colon,
2378 followed by the attribute's local name(). Since the namespace prefix
2379 is not unique (the same prefix can point to different namespaces
2380 and different prefixes can point to the same namespace), you
2381 shouldn't use qualifiedName(), but the resolved namespaceUri() and
2382 the attribute's local name().
2383 */
2384/*!
2385 \fn QStringRef QXmlStreamAttribute::prefix() const
2386 \since 4.4
2387 Returns the attribute's namespace prefix.
2388
2389 \sa name(), qualifiedName()
2390
2391*/
2392
2393/*! \fn QStringRef QXmlStreamAttribute::value() const
2394 Returns the attribute's value.
2395 */
2396
2397/*! \fn bool QXmlStreamAttribute::isDefault() const
2398
2399 Returns \c true if the parser added this attribute with a default
2400 value following an ATTLIST declaration in the DTD; otherwise
2401 returns \c false.
2402*/
2403/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &other) const
2404
2405 Compares this attribute with \a other and returns \c true if they are
2406 equal; otherwise returns \c false.
2407 */
2408/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &other) const
2409
2410 Compares this attribute with \a other and returns \c true if they are
2411 not equal; otherwise returns \c false.
2412 */
2413
2414
2415#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2416/*!
2417 Creates a copy of \a other.
2418 */
2419QXmlStreamAttribute::QXmlStreamAttribute(const QXmlStreamAttribute &other)
2420{
2421 *this = other;
2422}
2423
2424/*!
2425 Assigns \a other to this attribute.
2426 */
2427QXmlStreamAttribute& QXmlStreamAttribute::operator=(const QXmlStreamAttribute &other)
2428{
2429 m_name = other.m_name;
2430 m_namespaceUri = other.m_namespaceUri;
2431 m_qualifiedName = other.m_qualifiedName;
2432 m_value = other.m_value;
2433 m_isDefault = other.m_isDefault;
2434 return *this;
2435}
2436#endif
2437
2438/*!
2439 \class QXmlStreamAttributes
2440 \inmodule QtCore
2441 \since 4.3
2442 \reentrant
2443 \brief The QXmlStreamAttributes class represents a vector of QXmlStreamAttribute.
2444
2445 Attributes are returned by a QXmlStreamReader in
2446 \l{QXmlStreamReader::attributes()} {attributes()} when the reader
2447 reports a \l {QXmlStreamReader::StartElement}{start element}. The
2448 class can also be used with a QXmlStreamWriter as an argument to
2449 \l {QXmlStreamWriter::writeAttributes()}{writeAttributes()}.
2450
2451 The convenience function value() loops over the vector and returns
2452 an attribute value for a given namespaceUri and an attribute's
2453 name.
2454
2455 New attributes can be added with append().
2456
2457 \ingroup xml-tools
2458*/
2459
2460/*!
2461 \fn QXmlStreamAttributes::QXmlStreamAttributes()
2462
2463 A constructor for QXmlStreamAttributes.
2464*/
2465
2466/*!
2467 \typedef QXmlStreamNotationDeclarations
2468 \relates QXmlStreamNotationDeclaration
2469
2470 Synonym for QVector<QXmlStreamNotationDeclaration>.
2471*/
2472
2473
2474/*!
2475 \class QXmlStreamNotationDeclaration
2476 \inmodule QtCore
2477 \since 4.3
2478 \reentrant
2479 \brief The QXmlStreamNotationDeclaration class represents a DTD notation declaration.
2480
2481 \ingroup xml-tools
2482
2483 An notation declaration consists of a name(), a systemId(), and a publicId().
2484*/
2485
2486/*!
2487 Creates an empty notation declaration.
2488*/
2489QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2490{
2491}
2492
2493#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2494/*!
2495 Creates a copy of \a other.
2496 */
2497QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration(const QXmlStreamNotationDeclaration &other)
2498{
2499 *this = other;
2500}
2501
2502/*!
2503 Assigns \a other to this notation declaration.
2504 */
2505QXmlStreamNotationDeclaration& QXmlStreamNotationDeclaration::operator=(const QXmlStreamNotationDeclaration &other)
2506{
2507 m_name = other.m_name;
2508 m_systemId = other.m_systemId;
2509 m_publicId = other.m_publicId;
2510 return *this;
2511}
2512
2513/*!
2514Destructs this notation declaration.
2515*/
2516QXmlStreamNotationDeclaration::~QXmlStreamNotationDeclaration()
2517{
2518}
2519#endif
2520
2521/*! \fn QStringRef QXmlStreamNotationDeclaration::name() const
2522
2523Returns the notation name.
2524*/
2525/*! \fn QStringRef QXmlStreamNotationDeclaration::systemId() const
2526
2527Returns the system identifier.
2528*/
2529/*! \fn QStringRef QXmlStreamNotationDeclaration::publicId() const
2530
2531Returns the public identifier.
2532*/
2533
2534/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &other) const
2535
2536 Compares this notation declaration with \a other and returns \c true
2537 if they are equal; otherwise returns \c false.
2538 */
2539/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &other) const
2540
2541 Compares this notation declaration with \a other and returns \c true
2542 if they are not equal; otherwise returns \c false.
2543 */
2544
2545/*!
2546 \typedef QXmlStreamNamespaceDeclarations
2547 \relates QXmlStreamNamespaceDeclaration
2548
2549 Synonym for QVector<QXmlStreamNamespaceDeclaration>.
2550*/
2551
2552/*!
2553 \class QXmlStreamNamespaceDeclaration
2554 \inmodule QtCore
2555 \since 4.3
2556 \reentrant
2557 \brief The QXmlStreamNamespaceDeclaration class represents a namespace declaration.
2558
2559 \ingroup xml-tools
2560
2561 An namespace declaration consists of a prefix() and a namespaceUri().
2562*/
2563/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &other) const
2564
2565 Compares this namespace declaration with \a other and returns \c true
2566 if they are equal; otherwise returns \c false.
2567 */
2568/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &other) const
2569
2570 Compares this namespace declaration with \a other and returns \c true
2571 if they are not equal; otherwise returns \c false.
2572 */
2573
2574/*!
2575 Creates an empty namespace declaration.
2576*/
2577QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2578{
2579}
2580
2581/*!
2582 \since 4.4
2583
2584 Creates a namespace declaration with \a prefix and \a namespaceUri.
2585*/
2586QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(const QString &prefix, const QString &namespaceUri)
2587{
2588 m_prefix = prefix;
2589 m_namespaceUri = namespaceUri;
2590}
2591
2592#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2593/*!
2594 Creates a copy of \a other.
2595 */
2596QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &other)
2597{
2598 *this = other;
2599}
2600
2601/*!
2602 Assigns \a other to this namespace declaration.
2603 */
2604QXmlStreamNamespaceDeclaration& QXmlStreamNamespaceDeclaration::operator=(const QXmlStreamNamespaceDeclaration &other)
2605{
2606 m_prefix = other.m_prefix;
2607 m_namespaceUri = other.m_namespaceUri;
2608 return *this;
2609}
2610/*!
2611Destructs this namespace declaration.
2612*/
2613QXmlStreamNamespaceDeclaration::~QXmlStreamNamespaceDeclaration()
2614{
2615}
2616#endif
2617
2618/*! \fn QStringRef QXmlStreamNamespaceDeclaration::prefix() const
2619
2620Returns the prefix.
2621*/
2622/*! \fn QStringRef QXmlStreamNamespaceDeclaration::namespaceUri() const
2623
2624Returns the namespaceUri.
2625*/
2626
2627
2628
2629
2630/*!
2631 \typedef QXmlStreamEntityDeclarations
2632 \relates QXmlStreamEntityDeclaration
2633
2634 Synonym for QVector<QXmlStreamEntityDeclaration>.
2635*/
2636
2637/*!
2638 \class QXmlStreamStringRef
2639 \inmodule QtCore
2640 \since 4.3
2641 \internal
2642*/
2643
2644/*!
2645 \class QXmlStreamEntityDeclaration
2646 \inmodule QtCore
2647 \since 4.3
2648 \reentrant
2649 \brief The QXmlStreamEntityDeclaration class represents a DTD entity declaration.
2650
2651 \ingroup xml-tools
2652
2653 An entity declaration consists of a name(), a notationName(), a
2654 systemId(), a publicId(), and a value().
2655*/
2656
2657/*!
2658 Creates an empty entity declaration.
2659*/
2660QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2661{
2662}
2663
2664#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2665/*!
2666 Creates a copy of \a other.
2667 */
2668QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration(const QXmlStreamEntityDeclaration &other)
2669{
2670 *this = other;
2671}
2672
2673/*!
2674 Assigns \a other to this entity declaration.
2675 */
2676QXmlStreamEntityDeclaration& QXmlStreamEntityDeclaration::operator=(const QXmlStreamEntityDeclaration &other)
2677{
2678 m_name = other.m_name;
2679 m_notationName = other.m_notationName;
2680 m_systemId = other.m_systemId;
2681 m_publicId = other.m_publicId;
2682 m_value = other.m_value;
2683 return *this;
2684}
2685
2686/*!
2687 Destructs this entity declaration.
2688*/
2689QXmlStreamEntityDeclaration::~QXmlStreamEntityDeclaration()
2690{
2691}
2692#endif
2693
2694/*! \fn QXmlStreamStringRef::swap(QXmlStreamStringRef &other)
2695 \since 5.6
2696
2697 Swaps this string reference's contents with \a other.
2698 This function is very fast and never fails.
2699*/
2700
2701/*! \fn QStringRef QXmlStreamEntityDeclaration::name() const
2702
2703Returns the entity name.
2704*/
2705/*! \fn QStringRef QXmlStreamEntityDeclaration::notationName() const
2706
2707Returns the notation name.
2708*/
2709/*! \fn QStringRef QXmlStreamEntityDeclaration::systemId() const
2710
2711Returns the system identifier.
2712*/
2713/*! \fn QStringRef QXmlStreamEntityDeclaration::publicId() const
2714
2715Returns the public identifier.
2716*/
2717/*! \fn QStringRef QXmlStreamEntityDeclaration::value() const
2718
2719Returns the entity's value.
2720*/
2721
2722/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &other) const
2723
2724 Compares this entity declaration with \a other and returns \c true if
2725 they are equal; otherwise returns \c false.
2726 */
2727/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &other) const
2728
2729 Compares this entity declaration with \a other and returns \c true if
2730 they are not equal; otherwise returns \c false.
2731 */
2732
2733/*! Returns the value of the attribute \a name in the namespace
2734 described with \a namespaceUri, or an empty string reference if the
2735 attribute is not defined. The \a namespaceUri can be empty.
2736 */
2737QStringRef QXmlStreamAttributes::value(const QString &namespaceUri, const QString &name) const
2738{
2739 for (int i = 0; i < size(); ++i) {
2740 const QXmlStreamAttribute &attribute = at(i);
2741 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2742 return attribute.value();
2743 }
2744 return QStringRef();
2745}
2746
2747/*!\overload
2748 Returns the value of the attribute \a name in the namespace
2749 described with \a namespaceUri, or an empty string reference if the
2750 attribute is not defined. The \a namespaceUri can be empty.
2751 */
2752QStringRef QXmlStreamAttributes::value(const QString &namespaceUri, QLatin1String name) const
2753{
2754 for (int i = 0; i < size(); ++i) {
2755 const QXmlStreamAttribute &attribute = at(i);
2756 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2757 return attribute.value();
2758 }
2759 return QStringRef();
2760}
2761
2762/*!\overload
2763 Returns the value of the attribute \a name in the namespace
2764 described with \a namespaceUri, or an empty string reference if the
2765 attribute is not defined. The \a namespaceUri can be empty.
2766 */
2767QStringRef QXmlStreamAttributes::value(QLatin1String namespaceUri, QLatin1String name) const
2768{
2769 for (int i = 0; i < size(); ++i) {
2770 const QXmlStreamAttribute &attribute = at(i);
2771 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2772 return attribute.value();
2773 }
2774 return QStringRef();
2775}
2776
2777/*!\overload
2778
2779 Returns the value of the attribute with qualified name \a
2780 qualifiedName , or an empty string reference if the attribute is not
2781 defined. A qualified name is the raw name of an attribute in the XML
2782 data. It consists of the namespace prefix, followed by colon,
2783 followed by the attribute's local name. Since the namespace prefix
2784 is not unique (the same prefix can point to different namespaces and
2785 different prefixes can point to the same namespace), you shouldn't
2786 use qualified names, but a resolved namespaceUri and the attribute's
2787 local name.
2788 */
2789QStringRef QXmlStreamAttributes::value(const QString &qualifiedName) const
2790{
2791 for (int i = 0; i < size(); ++i) {
2792 const QXmlStreamAttribute &attribute = at(i);
2793 if (attribute.qualifiedName() == qualifiedName)
2794 return attribute.value();
2795 }
2796 return QStringRef();
2797}
2798
2799/*!\overload
2800
2801 Returns the value of the attribute with qualified name \a
2802 qualifiedName , or an empty string reference if the attribute is not
2803 defined. A qualified name is the raw name of an attribute in the XML
2804 data. It consists of the namespace prefix, followed by colon,
2805 followed by the attribute's local name. Since the namespace prefix
2806 is not unique (the same prefix can point to different namespaces and
2807 different prefixes can point to the same namespace), you shouldn't
2808 use qualified names, but a resolved namespaceUri and the attribute's
2809 local name.
2810 */
2811QStringRef QXmlStreamAttributes::value(QLatin1String qualifiedName) const
2812{
2813 for (int i = 0; i < size(); ++i) {
2814 const QXmlStreamAttribute &attribute = at(i);
2815 if (attribute.qualifiedName() == qualifiedName)
2816 return attribute.value();
2817 }
2818 return QStringRef();
2819}
2820
2821/*!Appends a new attribute with \a name in the namespace
2822 described with \a namespaceUri, and value \a value. The \a
2823 namespaceUri can be empty.
2824 */
2825void QXmlStreamAttributes::append(const QString &namespaceUri, const QString &name, const QString &value)
2826{
2827 append(t: QXmlStreamAttribute(namespaceUri, name, value));
2828}
2829
2830/*!\overload
2831 Appends a new attribute with qualified name \a qualifiedName and
2832 value \a value.
2833 */
2834void QXmlStreamAttributes::append(const QString &qualifiedName, const QString &value)
2835{
2836 append(t: QXmlStreamAttribute(qualifiedName, value));
2837}
2838
2839#ifndef QT_NO_XMLSTREAMREADER
2840
2841/*! \fn bool QXmlStreamReader::isStartDocument() const
2842 Returns \c true if tokenType() equals \l StartDocument; otherwise returns \c false.
2843*/
2844/*! \fn bool QXmlStreamReader::isEndDocument() const
2845 Returns \c true if tokenType() equals \l EndDocument; otherwise returns \c false.
2846*/
2847/*! \fn bool QXmlStreamReader::isStartElement() const
2848 Returns \c true if tokenType() equals \l StartElement; otherwise returns \c false.
2849*/
2850/*! \fn bool QXmlStreamReader::isEndElement() const
2851 Returns \c true if tokenType() equals \l EndElement; otherwise returns \c false.
2852*/
2853/*! \fn bool QXmlStreamReader::isCharacters() const
2854 Returns \c true if tokenType() equals \l Characters; otherwise returns \c false.
2855
2856 \sa isWhitespace(), isCDATA()
2857*/
2858/*! \fn bool QXmlStreamReader::isComment() const
2859 Returns \c true if tokenType() equals \l Comment; otherwise returns \c false.
2860*/
2861/*! \fn bool QXmlStreamReader::isDTD() const
2862 Returns \c true if tokenType() equals \l DTD; otherwise returns \c false.
2863*/
2864/*! \fn bool QXmlStreamReader::isEntityReference() const
2865 Returns \c true if tokenType() equals \l EntityReference; otherwise returns \c false.
2866*/
2867/*! \fn bool QXmlStreamReader::isProcessingInstruction() const
2868 Returns \c true if tokenType() equals \l ProcessingInstruction; otherwise returns \c false.
2869*/
2870
2871/*! Returns \c true if the reader reports characters that only consist
2872 of white-space; otherwise returns \c false.
2873
2874 \sa isCharacters(), text()
2875*/
2876bool QXmlStreamReader::isWhitespace() const
2877{
2878 Q_D(const QXmlStreamReader);
2879 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
2880}
2881
2882/*! Returns \c true if the reader reports characters that stem from a
2883 CDATA section; otherwise returns \c false.
2884
2885 \sa isCharacters(), text()
2886*/
2887bool QXmlStreamReader::isCDATA() const
2888{
2889 Q_D(const QXmlStreamReader);
2890 return d->type == QXmlStreamReader::Characters && d->isCDATA;
2891}
2892
2893
2894
2895/*!
2896 Returns \c true if this document has been declared standalone in the
2897 XML declaration; otherwise returns \c false.
2898
2899 If no XML declaration has been parsed, this function returns \c false.
2900 */
2901bool QXmlStreamReader::isStandaloneDocument() const
2902{
2903 Q_D(const QXmlStreamReader);
2904 return d->standalone;
2905}
2906
2907
2908/*!
2909 \since 4.4
2910
2911 If the tokenType() is \l StartDocument, this function returns the
2912 version string as specified in the XML declaration.
2913 Otherwise an empty string is returned.
2914 */
2915QStringRef QXmlStreamReader::documentVersion() const
2916{
2917 Q_D(const QXmlStreamReader);
2918 if (d->type == QXmlStreamReader::StartDocument)
2919 return d->documentVersion;
2920 return QStringRef();
2921}
2922
2923/*!
2924 \since 4.4
2925
2926 If the tokenType() is \l StartDocument, this function returns the
2927 encoding string as specified in the XML declaration.
2928 Otherwise an empty string is returned.
2929 */
2930QStringRef QXmlStreamReader::documentEncoding() const
2931{
2932 Q_D(const QXmlStreamReader);
2933 if (d->type == QXmlStreamReader::StartDocument)
2934 return d->documentEncoding;
2935 return QStringRef();
2936}
2937
2938#endif // QT_NO_XMLSTREAMREADER
2939
2940/*!
2941 \class QXmlStreamWriter
2942 \inmodule QtCore
2943 \since 4.3
2944 \reentrant
2945
2946 \brief The QXmlStreamWriter class provides an XML writer with a
2947 simple streaming API.
2948
2949 \ingroup xml-tools
2950
2951 QXmlStreamWriter is the counterpart to QXmlStreamReader for writing
2952 XML. Like its related class, it operates on a QIODevice specified
2953 with setDevice(). The API is simple and straightforward: for every
2954 XML token or event you want to write, the writer provides a
2955 specialized function.
2956
2957 You start a document with writeStartDocument() and end it with
2958 writeEndDocument(). This will implicitly close all remaining open
2959 tags.
2960
2961 Element tags are opened with writeStartElement() followed by
2962 writeAttribute() or writeAttributes(), element content, and then
2963 writeEndElement(). A shorter form writeEmptyElement() can be used
2964 to write empty elements, followed by writeAttributes().
2965
2966 Element content consists of either characters, entity references or
2967 nested elements. It is written with writeCharacters(), which also
2968 takes care of escaping all forbidden characters and character
2969 sequences, writeEntityReference(), or subsequent calls to
2970 writeStartElement(). A convenience method writeTextElement() can be
2971 used for writing terminal elements that contain nothing but text.
2972
2973 The following abridged code snippet shows the basic use of the class
2974 to write formatted XML with indentation:
2975
2976 \snippet qxmlstreamwriter/main.cpp start stream
2977 \dots
2978 \snippet qxmlstreamwriter/main.cpp write element
2979 \dots
2980 \snippet qxmlstreamwriter/main.cpp finish stream
2981
2982 QXmlStreamWriter takes care of prefixing namespaces, all you have to
2983 do is specify the \c namespaceUri when writing elements or
2984 attributes. If you must conform to certain prefixes, you can force
2985 the writer to use them by declaring the namespaces manually with
2986 either writeNamespace() or writeDefaultNamespace(). Alternatively,
2987 you can bypass the stream writer's namespace support and use
2988 overloaded methods that take a qualified name instead. The namespace
2989 \e http://www.w3.org/XML/1998/namespace is implicit and mapped to the
2990 prefix \e xml.
2991
2992 The stream writer can automatically format the generated XML data by
2993 adding line-breaks and indentation to empty sections between
2994 elements, making the XML data more readable for humans and easier to
2995 work with for most source code management systems. The feature can
2996 be turned on with the \l autoFormatting property, and customized
2997 with the \l autoFormattingIndent property.
2998
2999 Other functions are writeCDATA(), writeComment(),
3000 writeProcessingInstruction(), and writeDTD(). Chaining of XML
3001 streams is supported with writeCurrentToken().
3002
3003 By default, QXmlStreamWriter encodes XML in UTF-8. Different
3004 encodings can be enforced using setCodec().
3005
3006 If an error occurs while writing to the underlying device, hasError()
3007 starts returning true and subsequent writes are ignored.
3008
3009 The \l{QXmlStream Bookmarks Example} illustrates how to use a
3010 stream writer to write an XML bookmark file (XBEL) that
3011 was previously read in by a QXmlStreamReader.
3012
3013*/
3014
3015#ifndef QT_NO_XMLSTREAMWRITER
3016
3017class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack {
3018 QXmlStreamWriter *q_ptr;
3019 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3020public:
3021 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3022 ~QXmlStreamWriterPrivate() {
3023 if (deleteDevice)
3024 delete device;
3025#if QT_CONFIG(textcodec)
3026 delete encoder;
3027#endif
3028 }
3029
3030 void write(const QStringRef &);
3031 void write(const QString &);
3032 void writeEscaped(const QString &, bool escapeWhitespace = false);
3033 void write(const char *s, int len);
3034 template <int N> void write(const char (&s)[N]) { write(s, N - 1); }
3035 bool finishStartElement(bool contents = true);
3036 void writeStartElement(const QString &namespaceUri, const QString &name);
3037 QIODevice *device;
3038 QString *stringDevice;
3039 uint deleteDevice :1;
3040 uint inStartElement :1;
3041 uint inEmptyElement :1;
3042 uint lastWasStartElement :1;
3043 uint wroteSomething :1;
3044 uint hasIoError :1;
3045 uint hasEncodingError :1;
3046 uint autoFormatting :1;
3047 uint isCodecASCIICompatible :1;
3048 QByteArray autoFormattingIndent;
3049 NamespaceDeclaration emptyNamespace;
3050 int lastNamespaceDeclaration;
3051
3052#if QT_CONFIG(textcodec)
3053 QTextCodec *codec;
3054 QTextEncoder *encoder;
3055#endif
3056 void checkIfASCIICompatibleCodec();
3057
3058 NamespaceDeclaration &findNamespace(const QString &namespaceUri, bool writeDeclaration = false, bool noDefault = false);
3059 void writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration);
3060
3061 int namespacePrefixCount;
3062
3063 void indent(int level);
3064};
3065
3066
3067QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3068 :autoFormattingIndent(4, ' ')
3069{
3070 q_ptr = q;
3071 device = nullptr;
3072 stringDevice = nullptr;
3073 deleteDevice = false;
3074#if QT_CONFIG(textcodec)
3075 codec = QTextCodec::codecForMib(mib: 106); // utf8
3076 encoder = codec->makeEncoder(flags: QTextCodec::IgnoreHeader); // no byte order mark for utf8
3077#endif
3078 checkIfASCIICompatibleCodec();
3079 inStartElement = inEmptyElement = false;
3080 wroteSomething = false;
3081 hasIoError = false;
3082 hasEncodingError = false;
3083 lastWasStartElement = false;
3084 lastNamespaceDeclaration = 1;
3085 autoFormatting = false;
3086 namespacePrefixCount = 0;
3087}
3088
3089void QXmlStreamWriterPrivate::checkIfASCIICompatibleCodec()
3090{
3091#if QT_CONFIG(textcodec)
3092 Q_ASSERT(encoder);
3093 // test ASCII-compatibility using the letter 'a'
3094 QChar letterA = QLatin1Char('a');
3095 const QByteArray bytesA = encoder->fromUnicode(uc: &letterA, len: 1);
3096 const bool isCodecASCIICompatibleA = (bytesA.count() == 1) && (bytesA[0] == 0x61) ;
3097 QChar letterLess = QLatin1Char('<');
3098 const QByteArray bytesLess = encoder->fromUnicode(uc: &letterLess, len: 1);
3099 const bool isCodecASCIICompatibleLess = (bytesLess.count() == 1) && (bytesLess[0] == 0x3C) ;
3100 isCodecASCIICompatible = isCodecASCIICompatibleA && isCodecASCIICompatibleLess ;
3101#else
3102 isCodecASCIICompatible = true;
3103#endif
3104}
3105
3106void QXmlStreamWriterPrivate::write(const QStringRef &s)
3107{
3108 if (device) {
3109 if (hasIoError)
3110 return;
3111#if !QT_CONFIG(textcodec)
3112 QByteArray bytes = s.toLatin1();
3113#else
3114 QByteArray bytes = encoder->fromUnicode(uc: s.constData(), len: s.size());
3115 if (encoder->hasFailure()) {
3116 hasEncodingError = true;
3117 return;
3118 }
3119#endif
3120 if (device->write(data: bytes) != bytes.size())
3121 hasIoError = true;
3122 }
3123 else if (stringDevice)
3124 s.appendTo(string: stringDevice);
3125 else
3126 qWarning(msg: "QXmlStreamWriter: No device");
3127}
3128
3129void QXmlStreamWriterPrivate::write(const QString &s)
3130{
3131 if (device) {
3132 if (hasIoError)
3133 return;
3134#if !QT_CONFIG(textcodec)
3135 QByteArray bytes = s.toLatin1();
3136#else
3137 QByteArray bytes = encoder->fromUnicode(str: s);
3138 if (encoder->hasFailure()) {
3139 hasEncodingError = true;
3140 return;
3141 }
3142#endif
3143 if (device->write(data: bytes) != bytes.size())
3144 hasIoError = true;
3145 }
3146 else if (stringDevice)
3147 stringDevice->append(s);
3148 else
3149 qWarning(msg: "QXmlStreamWriter: No device");
3150}
3151
3152void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespace)
3153{
3154 QString escaped;
3155 escaped.reserve(asize: s.size());
3156 for ( int i = 0; i < s.size(); ++i ) {
3157 QChar c = s.at(i);
3158 switch (c.unicode()) {
3159 case '<':
3160 escaped.append(s: QLatin1String("&lt;"));
3161 break;
3162 case '>':
3163 escaped.append(s: QLatin1String("&gt;"));
3164 break;
3165 case '&':
3166 escaped.append(s: QLatin1String("&amp;"));
3167 break;
3168 case '\"':
3169 escaped.append(s: QLatin1String("&quot;"));
3170 break;
3171 case '\t':
3172 if (escapeWhitespace)
3173 escaped.append(s: QLatin1String("&#9;"));
3174 else
3175 escaped += c;
3176 break;
3177 case '\n':
3178 if (escapeWhitespace)
3179 escaped.append(s: QLatin1String("&#10;"));
3180 else
3181 escaped += c;
3182 break;
3183 case '\v':
3184 case '\f':
3185 hasEncodingError = true;
3186 break;
3187 case '\r':
3188 if (escapeWhitespace)
3189 escaped.append(s: QLatin1String("&#13;"));
3190 else
3191 escaped += c;
3192 break;
3193 default:
3194 if (c.unicode() > 0x1f && c.unicode() < 0xfffe)
3195 escaped += c;
3196 else
3197 hasEncodingError = true;
3198 break;
3199 }
3200 }
3201 write(s: escaped);
3202}
3203
3204// Converts from ASCII to output encoding
3205void QXmlStreamWriterPrivate::write(const char *s, int len)
3206{
3207 if (device) {
3208 if (hasIoError)
3209 return;
3210 if (isCodecASCIICompatible) {
3211 if (device->write(data: s, len) != len)
3212 hasIoError = true;
3213 return;
3214 }
3215 }
3216
3217 write(s: QString::fromLatin1(str: s, size: len));
3218}
3219
3220void QXmlStreamWriterPrivate::writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration) {
3221 if (namespaceDeclaration.prefix.isEmpty()) {
3222 write(s: " xmlns=\"");
3223 write(s: namespaceDeclaration.namespaceUri);
3224 write(s: "\"");
3225 } else {
3226 write(s: " xmlns:");
3227 write(s: namespaceDeclaration.prefix);
3228 write(s: "=\"");
3229 write(s: namespaceDeclaration.namespaceUri);
3230 write(s: "\"");
3231 }
3232}
3233
3234bool QXmlStreamWriterPrivate::finishStartElement(bool contents)
3235{
3236 bool hadSomethingWritten = wroteSomething;
3237 wroteSomething = contents;
3238 if (!inStartElement)
3239 return hadSomethingWritten;
3240
3241 if (inEmptyElement) {
3242 write(s: "/>");
3243 QXmlStreamWriterPrivate::Tag &tag = tagStack_pop();
3244 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3245 lastWasStartElement = false;
3246 } else {
3247 write(s: ">");
3248 }
3249 inStartElement = inEmptyElement = false;
3250 lastNamespaceDeclaration = namespaceDeclarations.size();
3251 return hadSomethingWritten;
3252}
3253
3254QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(const QString &namespaceUri, bool writeDeclaration, bool noDefault)
3255{
3256 for (int j = namespaceDeclarations.size() - 1; j >= 0; --j) {
3257 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations[j];
3258 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3259 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3260 return namespaceDeclaration;
3261 }
3262 }
3263 if (namespaceUri.isEmpty())
3264 return emptyNamespace;
3265 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3266 if (namespaceUri.isEmpty()) {
3267 namespaceDeclaration.prefix.clear();
3268 } else {
3269 QString s;
3270 int n = ++namespacePrefixCount;
3271 forever {
3272 s = QLatin1Char('n') + QString::number(n++);
3273 int j = namespaceDeclarations.size() - 2;
3274 while (j >= 0 && namespaceDeclarations.at(index: j).prefix != s)
3275 --j;
3276 if (j < 0)
3277 break;
3278 }
3279 namespaceDeclaration.prefix = addToStringStorage(s);
3280 }
3281 namespaceDeclaration.namespaceUri = addToStringStorage(s: namespaceUri);
3282 if (writeDeclaration)
3283 writeNamespaceDeclaration(namespaceDeclaration);
3284 return namespaceDeclaration;
3285}
3286
3287
3288
3289void QXmlStreamWriterPrivate::indent(int level)
3290{
3291 write(s: "\n");
3292 for (int i = level; i > 0; --i)
3293 write(s: autoFormattingIndent.constData(), len: autoFormattingIndent.length());
3294}
3295
3296
3297/*!
3298 Constructs a stream writer.
3299
3300 \sa setDevice()
3301 */
3302QXmlStreamWriter::QXmlStreamWriter()
3303 : d_ptr(new QXmlStreamWriterPrivate(this))
3304{
3305}
3306
3307/*!
3308 Constructs a stream writer that writes into \a device;
3309 */
3310QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3311 : d_ptr(new QXmlStreamWriterPrivate(this))
3312{
3313 Q_D(QXmlStreamWriter);
3314 d->device = device;
3315}
3316
3317/*! Constructs a stream writer that writes into \a array. This is the
3318 same as creating an xml writer that operates on a QBuffer device
3319 which in turn operates on \a array.
3320 */
3321QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3322 : d_ptr(new QXmlStreamWriterPrivate(this))
3323{
3324 Q_D(QXmlStreamWriter);
3325 d->device = new QBuffer(array);
3326 d->device->open(mode: QIODevice::WriteOnly);
3327 d->deleteDevice = true;
3328}
3329
3330
3331/*! Constructs a stream writer that writes into \a string.
3332 *
3333 * Note that when writing to QString, QXmlStreamWriter ignores the codec set
3334 * with setCodec(). See that function for more information.
3335 */
3336QXmlStreamWriter::QXmlStreamWriter(QString *string)
3337 : d_ptr(new QXmlStreamWriterPrivate(this))
3338{
3339 Q_D(QXmlStreamWriter);
3340 d->stringDevice = string;
3341}
3342
3343/*!
3344 Destructor.
3345*/
3346QXmlStreamWriter::~QXmlStreamWriter()
3347{
3348}
3349
3350
3351/*!
3352 Sets the current device to \a device. If you want the stream to
3353 write into a QByteArray, you can create a QBuffer device.
3354
3355 \sa device()
3356*/
3357void QXmlStreamWriter::setDevice(QIODevice *device)
3358{
3359 Q_D(QXmlStreamWriter);
3360 if (device == d->device)
3361 return;
3362 d->stringDevice = nullptr;
3363 if (d->deleteDevice) {
3364 delete d->device;
3365 d->deleteDevice = false;
3366 }
3367 d->device = device;
3368}
3369
3370/*!
3371 Returns the current device associated with the QXmlStreamWriter,
3372 or \nullptr if no device has been assigned.
3373
3374 \sa setDevice()
3375*/
3376QIODevice *QXmlStreamWriter::device() const
3377{
3378 Q_D(const QXmlStreamWriter);
3379 return d->device;
3380}
3381
3382
3383#if QT_CONFIG(textcodec)
3384/*!
3385 Sets the codec for this stream to \a codec. The codec is used for
3386 encoding any data that is written. By default, QXmlStreamWriter
3387 uses UTF-8.
3388
3389 The encoding information is stored in the initial xml tag which
3390 gets written when you call writeStartDocument(). Call this
3391 function before calling writeStartDocument().
3392
3393 \note When writing the XML to a QString, the codec information is ignored
3394 and the XML header will not include any encoding information, since all
3395 QStrings are UTF-16. If you later convert the QString to an 8-bit format,
3396 you must arrange for the encoding information to be transmitted
3397 out-of-band.
3398
3399 \sa codec()
3400*/
3401void QXmlStreamWriter::setCodec(QTextCodec *codec)
3402{
3403 Q_D(QXmlStreamWriter);
3404 if (codec) {
3405 d->codec = codec;
3406 delete d->encoder;
3407 d->encoder = codec->makeEncoder(flags: QTextCodec::IgnoreHeader); // no byte order mark for utf8
3408 d->checkIfASCIICompatibleCodec();
3409 }
3410}
3411
3412/*!
3413 Sets the codec for this stream to the QTextCodec for the encoding
3414 specified by \a codecName. Common values for \c codecName include
3415 "ISO 8859-1", "UTF-8", and "UTF-16". If the encoding isn't
3416 recognized, nothing happens.
3417
3418 \note When writing the XML to a QString, the codec information is ignored
3419 and the XML header will not include any encoding information, since all
3420 QStrings are UTF-16. If you later convert the QString to an 8-bit format,
3421 you must arrange for the encoding information to be transmitted
3422 out-of-band.
3423
3424 \sa QTextCodec::codecForName()
3425*/
3426void QXmlStreamWriter::setCodec(const char *codecName)
3427{
3428 setCodec(QTextCodec::codecForName(name: codecName));
3429}
3430
3431/*!
3432 Returns the codec that is currently assigned to the stream.
3433
3434 \sa setCodec()
3435*/
3436QTextCodec *QXmlStreamWriter::codec() const
3437{
3438 Q_D(const QXmlStreamWriter);
3439 return d->codec;
3440}
3441#endif // textcodec
3442
3443/*!
3444 \property QXmlStreamWriter::autoFormatting
3445 \since 4.4
3446 The auto-formatting flag of the stream writer
3447
3448 This property controls whether or not the stream writer
3449 automatically formats the generated XML data. If enabled, the
3450 writer automatically adds line-breaks and indentation to empty
3451 sections between elements (ignorable whitespace). The main purpose
3452 of auto-formatting is to split the data into several lines, and to
3453 increase readability for a human reader. The indentation depth can
3454 be controlled through the \l autoFormattingIndent property.
3455
3456 By default, auto-formatting is disabled.
3457*/
3458
3459/*!
3460 \since 4.4
3461
3462 Enables auto formatting if \a enable is \c true, otherwise
3463 disables it.
3464
3465 The default value is \c false.
3466 */
3467void QXmlStreamWriter::setAutoFormatting(bool enable)
3468{
3469 Q_D(QXmlStreamWriter);
3470 d->autoFormatting = enable;
3471}
3472
3473/*!
3474 \since 4.4
3475
3476 Returns \c true if auto formattting is enabled, otherwise \c false.
3477 */
3478bool QXmlStreamWriter::autoFormatting() const
3479{
3480 Q_D(const QXmlStreamWriter);
3481 return d->autoFormatting;
3482}
3483
3484/*!
3485 \property QXmlStreamWriter::autoFormattingIndent
3486 \since 4.4
3487
3488 \brief the number of spaces or tabs used for indentation when
3489 auto-formatting is enabled. Positive numbers indicate spaces,
3490 negative numbers tabs.
3491
3492 The default indentation is 4.
3493
3494 \sa autoFormatting
3495*/
3496
3497
3498void QXmlStreamWriter::setAutoFormattingIndent(int spacesOrTabs)
3499{
3500 Q_D(QXmlStreamWriter);
3501 d->autoFormattingIndent = QByteArray(qAbs(t: spacesOrTabs), spacesOrTabs >= 0 ? ' ' : '\t');
3502}
3503
3504int QXmlStreamWriter::autoFormattingIndent() const
3505{
3506 Q_D(const QXmlStreamWriter);
3507 return d->autoFormattingIndent.count(c: ' ') - d->autoFormattingIndent.count(c: '\t');
3508}
3509
3510/*!
3511 Returns \c true if writing failed.
3512
3513 This can happen if the stream failed to write to the underlying
3514 device or if the data to be written contained invalid characters.
3515
3516 The error status is never reset. Writes happening after the error
3517 occurred may be ignored, even if the error condition is cleared.
3518 */
3519bool QXmlStreamWriter::hasError() const
3520{
3521 Q_D(const QXmlStreamWriter);
3522 return d->hasIoError || d->hasEncodingError;
3523}
3524
3525/*!
3526 \overload
3527 Writes an attribute with \a qualifiedName and \a value.
3528
3529
3530 This function can only be called after writeStartElement() before
3531 any content is written, or after writeEmptyElement().
3532 */
3533void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QString &value)
3534{
3535 Q_D(QXmlStreamWriter);
3536 Q_ASSERT(d->inStartElement);
3537 Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
3538 d->write(s: " ");
3539 d->write(s: qualifiedName);
3540 d->write(s: "=\"");
3541 d->writeEscaped(s: value, escapeWhitespace: true);
3542 d->write(s: "\"");
3543}
3544
3545/*! Writes an attribute with \a name and \a value, prefixed for
3546 the specified \a namespaceUri. If the namespace has not been
3547 declared yet, QXmlStreamWriter will generate a namespace declaration
3548 for it.
3549
3550 This function can only be called after writeStartElement() before
3551 any content is written, or after writeEmptyElement().
3552 */
3553void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString &name, const QString &value)
3554{
3555 Q_D(QXmlStreamWriter);
3556 Q_ASSERT(d->inStartElement);
3557 Q_ASSERT(!name.contains(QLatin1Char(':')));
3558 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri, writeDeclaration: true, noDefault: true);
3559 d->write(s: " ");
3560 if (!namespaceDeclaration.prefix.isEmpty()) {
3561 d->write(s: namespaceDeclaration.prefix);
3562 d->write(s: ":");
3563 }
3564 d->write(s: name);
3565 d->write(s: "=\"");
3566 d->writeEscaped(s: value, escapeWhitespace: true);
3567 d->write(s: "\"");
3568}
3569
3570/*!
3571 \overload
3572
3573 Writes the \a attribute.
3574
3575 This function can only be called after writeStartElement() before
3576 any content is written, or after writeEmptyElement().
3577 */
3578void QXmlStreamWriter::writeAttribute(const QXmlStreamAttribute& attribute)
3579{
3580 if (attribute.namespaceUri().isEmpty())
3581 writeAttribute(qualifiedName: attribute.qualifiedName().toString(),
3582 value: attribute.value().toString());
3583 else
3584 writeAttribute(namespaceUri: attribute.namespaceUri().toString(),
3585 name: attribute.name().toString(),
3586 value: attribute.value().toString());
3587}
3588
3589
3590/*! Writes the attribute vector \a attributes. If a namespace
3591 referenced in an attribute not been declared yet, QXmlStreamWriter
3592 will generate a namespace declaration for it.
3593
3594 This function can only be called after writeStartElement() before
3595 any content is written, or after writeEmptyElement().
3596
3597 \sa writeAttribute(), writeNamespace()
3598 */
3599void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes& attributes)
3600{
3601 Q_D(QXmlStreamWriter);
3602 Q_ASSERT(d->inStartElement);
3603 Q_UNUSED(d);
3604 for (int i = 0; i < attributes.size(); ++i)
3605 writeAttribute(attribute: attributes.at(i));
3606}
3607
3608
3609/*! Writes \a text as CDATA section. If \a text contains the
3610 forbidden character sequence "]]>", it is split into different CDATA
3611 sections.
3612
3613 This function mainly exists for completeness. Normally you should
3614 not need use it, because writeCharacters() automatically escapes all
3615 non-content characters.
3616 */
3617void QXmlStreamWriter::writeCDATA(const QString &text)
3618{
3619 Q_D(QXmlStreamWriter);
3620 d->finishStartElement();
3621 QString copy(text);
3622 copy.replace(before: QLatin1String("]]>"), after: QLatin1String("]]]]><![CDATA[>"));
3623 d->write(s: "<![CDATA[");
3624 d->write(s: copy);
3625 d->write(s: "]]>");
3626}
3627
3628
3629/*! Writes \a text. The characters "<", "&", and "\"" are escaped as entity
3630 references "&lt;", "&amp;, and "&quot;". To avoid the forbidden sequence
3631 "]]>", ">" is also escaped as "&gt;".
3632
3633 \sa writeEntityReference()
3634 */
3635void QXmlStreamWriter::writeCharacters(const QString &text)
3636{
3637 Q_D(QXmlStreamWriter);
3638 d->finishStartElement();
3639 d->writeEscaped(s: text);
3640}
3641
3642
3643/*! Writes \a text as XML comment, where \a text must not contain the
3644 forbidden sequence "--" or end with "-". Note that XML does not
3645 provide any way to escape "-" in a comment.
3646 */
3647void QXmlStreamWriter::writeComment(const QString &text)
3648{
3649 Q_D(QXmlStreamWriter);
3650 Q_ASSERT(!text.contains(QLatin1String("--")) && !text.endsWith(QLatin1Char('-')));
3651 if (!d->finishStartElement(contents: false) && d->autoFormatting)
3652 d->indent(level: d->tagStack.size());
3653 d->write(s: "<!--");
3654 d->write(s: text);
3655 d->write(s: "-->");
3656 d->inStartElement = d->lastWasStartElement = false;
3657}
3658
3659
3660/*! Writes a DTD section. The \a dtd represents the entire
3661 doctypedecl production from the XML 1.0 specification.
3662 */
3663void QXmlStreamWriter::writeDTD(const QString &dtd)
3664{
3665 Q_D(QXmlStreamWriter);
3666 d->finishStartElement();
3667 if (d->autoFormatting)
3668 d->write(s: "\n");
3669 d->write(s: dtd);
3670 if (d->autoFormatting)
3671 d->write(s: "\n");
3672}
3673
3674
3675
3676/*! \overload
3677 Writes an empty element with qualified name \a qualifiedName.
3678 Subsequent calls to writeAttribute() will add attributes to this element.
3679*/
3680void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName)
3681{
3682 Q_D(QXmlStreamWriter);
3683 Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
3684 d->writeStartElement(namespaceUri: QString(), name: qualifiedName);
3685 d->inEmptyElement = true;
3686}
3687
3688
3689/*! Writes an empty element with \a name, prefixed for the specified
3690 \a namespaceUri. If the namespace has not been declared,
3691 QXmlStreamWriter will generate a namespace declaration for it.
3692 Subsequent calls to writeAttribute() will add attributes to this element.
3693
3694 \sa writeNamespace()
3695 */
3696void QXmlStreamWriter::writeEmptyElement(const QString &namespaceUri, const QString &name)
3697{
3698 Q_D(QXmlStreamWriter);
3699 Q_ASSERT(!name.contains(QLatin1Char(':')));
3700 d->writeStartElement(namespaceUri, name);
3701 d->inEmptyElement = true;
3702}
3703
3704
3705/*!\overload
3706 Writes a text element with \a qualifiedName and \a text.
3707
3708
3709 This is a convenience function equivalent to:
3710 \snippet code/src_corelib_xml_qxmlstream.cpp 1
3711
3712*/
3713void QXmlStreamWriter::writeTextElement(const QString &qualifiedName, const QString &text)
3714{
3715 writeStartElement(qualifiedName);
3716 writeCharacters(text);
3717 writeEndElement();
3718}
3719
3720/*! Writes a text element with \a name, prefixed for the specified \a
3721 namespaceUri, and \a text. If the namespace has not been
3722 declared, QXmlStreamWriter will generate a namespace declaration
3723 for it.
3724
3725
3726 This is a convenience function equivalent to:
3727 \snippet code/src_corelib_xml_qxmlstream.cpp 2
3728
3729*/
3730void QXmlStreamWriter::writeTextElement(const QString &namespaceUri, const QString &name, const QString &text)
3731{
3732 writeStartElement(namespaceUri, name);
3733 writeCharacters(text);
3734 writeEndElement();
3735}
3736
3737
3738/*!
3739 Closes all remaining open start elements and writes a newline.
3740
3741 \sa writeStartDocument()
3742 */
3743void QXmlStreamWriter::writeEndDocument()
3744{
3745 Q_D(QXmlStreamWriter);
3746 while (d->tagStack.size())
3747 writeEndElement();
3748 d->write(s: "\n");
3749}
3750
3751/*!
3752 Closes the previous start element.
3753
3754 \sa writeStartElement()
3755 */
3756void QXmlStreamWriter::writeEndElement()
3757{
3758 Q_D(QXmlStreamWriter);
3759 if (d->tagStack.isEmpty())
3760 return;
3761
3762 // shortcut: if nothing was written, close as empty tag
3763 if (d->inStartElement && !d->inEmptyElement) {
3764 d->write(s: "/>");
3765 d->lastWasStartElement = d->inStartElement = false;
3766 QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop();
3767 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3768 return;
3769 }
3770
3771 if (!d->finishStartElement(contents: false) && !d->lastWasStartElement && d->autoFormatting)
3772 d->indent(level: d->tagStack.size()-1);
3773 if (d->tagStack.isEmpty())
3774 return;
3775 d->lastWasStartElement = false;
3776 QXmlStreamWriterPrivate::Tag &tag = d->tagStack_pop();
3777 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3778 d->write(s: "</");
3779 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
3780 d->write(s: tag.namespaceDeclaration.prefix);
3781 d->write(s: ":");
3782 }
3783 d->write(s: tag.name);
3784 d->write(s: ">");
3785}
3786
3787
3788
3789/*!
3790 Writes the entity reference \a name to the stream, as "&\a{name};".
3791 */
3792void QXmlStreamWriter::writeEntityReference(const QString &name)
3793{
3794 Q_D(QXmlStreamWriter);
3795 d->finishStartElement();
3796 d->write(s: "&");
3797 d->write(s: name);
3798 d->write(s: ";");
3799}
3800
3801
3802/*! Writes a namespace declaration for \a namespaceUri with \a
3803 prefix. If \a prefix is empty, QXmlStreamWriter assigns a unique
3804 prefix consisting of the letter 'n' followed by a number.
3805
3806 If writeStartElement() or writeEmptyElement() was called, the
3807 declaration applies to the current element; otherwise it applies to
3808 the next child element.
3809
3810 Note that the prefix \e xml is both predefined and reserved for
3811 \e http://www.w3.org/XML/1998/namespace, which in turn cannot be
3812 bound to any other prefix. The prefix \e xmlns and its URI
3813 \e http://www.w3.org/2000/xmlns/ are used for the namespace mechanism
3814 itself and thus completely forbidden in declarations.
3815
3816 */
3817void QXmlStreamWriter::writeNamespace(const QString &namespaceUri, const QString &prefix)
3818{
3819 Q_D(QXmlStreamWriter);
3820 Q_ASSERT(prefix != QLatin1String("xmlns"));
3821 if (prefix.isEmpty()) {
3822 d->findNamespace(namespaceUri, writeDeclaration: d->inStartElement);
3823 } else {
3824 Q_ASSERT(!((prefix == QLatin1String("xml")) ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace"))));
3825 Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/"));
3826 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
3827 namespaceDeclaration.prefix = d->addToStringStorage(s: prefix);
3828 namespaceDeclaration.namespaceUri = d->addToStringStorage(s: namespaceUri);
3829 if (d->inStartElement)
3830 d->writeNamespaceDeclaration(namespaceDeclaration);
3831 }
3832}
3833
3834
3835/*! Writes a default namespace declaration for \a namespaceUri.
3836
3837 If writeStartElement() or writeEmptyElement() was called, the
3838 declaration applies to the current element; otherwise it applies to
3839 the next child element.
3840
3841 Note that the namespaces \e http://www.w3.org/XML/1998/namespace
3842 (bound to \e xmlns) and \e http://www.w3.org/2000/xmlns/ (bound to
3843 \e xml) by definition cannot be declared as default.
3844 */
3845void QXmlStreamWriter::writeDefaultNamespace(const QString &namespaceUri)
3846{
3847 Q_D(QXmlStreamWriter);
3848 Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/XML/1998/namespace"));
3849 Q_ASSERT(namespaceUri != QLatin1String("http://www.w3.org/2000/xmlns/"));
3850 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
3851 namespaceDeclaration.prefix.clear();
3852 namespaceDeclaration.namespaceUri = d->addToStringStorage(s: namespaceUri);
3853 if (d->inStartElement)
3854 d->writeNamespaceDeclaration(namespaceDeclaration);
3855}
3856
3857
3858/*!
3859 Writes an XML processing instruction with \a target and \a data,
3860 where \a data must not contain the sequence "?>".
3861 */
3862void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const QString &data)
3863{
3864 Q_D(QXmlStreamWriter);
3865 Q_ASSERT(!data.contains(QLatin1String("?>")));
3866 if (!d->finishStartElement(contents: false) && d->autoFormatting)
3867 d->indent(level: d->tagStack.size());
3868 d->write(s: "<?");
3869 d->write(s: target);
3870 if (!data.isNull()) {
3871 d->write(s: " ");
3872 d->write(s: data);
3873 }
3874 d->write(s: "?>");
3875}
3876
3877
3878
3879/*!\overload
3880
3881 Writes a document start with XML version number "1.0". This also
3882 writes the encoding information.
3883
3884 \sa writeEndDocument(), setCodec()
3885 \since 4.5
3886 */
3887void QXmlStreamWriter::writeStartDocument()
3888{
3889 writeStartDocument(version: QLatin1String("1.0"));
3890}
3891
3892
3893/*!
3894 Writes a document start with the XML version number \a version.
3895
3896 \sa writeEndDocument()
3897 */
3898void QXmlStreamWriter::writeStartDocument(const QString &version)
3899{
3900 Q_D(QXmlStreamWriter);
3901 d->finishStartElement(contents: false);
3902 d->write(s: "<?xml version=\"");
3903 d->write(s: version);
3904 if (d->device) { // stringDevice does not get any encoding
3905 d->write(s: "\" encoding=\"");
3906#if !QT_CONFIG(textcodec)
3907 d->write("iso-8859-1");
3908#else
3909 const QByteArray name = d->codec->name();
3910 d->write(s: name.constData(), len: name.length());
3911#endif
3912 }
3913 d->write(s: "\"?>");
3914}
3915
3916/*! Writes a document start with the XML version number \a version
3917 and a standalone attribute \a standalone.
3918
3919 \sa writeEndDocument()
3920 \since 4.5
3921 */
3922void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalone)
3923{
3924 Q_D(QXmlStreamWriter);
3925 d->finishStartElement(contents: false);
3926 d->write(s: "<?xml version=\"");
3927 d->write(s: version);
3928 if (d->device) { // stringDevice does not get any encoding
3929 d->write(s: "\" encoding=\"");
3930#if !QT_CONFIG(textcodec)
3931 d->write("iso-8859-1");
3932#else
3933 const QByteArray name = d->codec->name();
3934 d->write(s: name.constData(), len: name.length());
3935#endif
3936 }
3937 if (standalone)
3938 d->write(s: "\" standalone=\"yes\"?>");
3939 else
3940 d->write(s: "\" standalone=\"no\"?>");
3941}
3942
3943
3944/*!\overload
3945
3946 Writes a start element with \a qualifiedName. Subsequent calls to
3947 writeAttribute() will add attributes to this element.
3948
3949 \sa writeEndElement(), writeEmptyElement()
3950 */
3951void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
3952{
3953 Q_D(QXmlStreamWriter);
3954 Q_ASSERT(qualifiedName.count(QLatin1Char(':')) <= 1);
3955 d->writeStartElement(namespaceUri: QString(), name: qualifiedName);
3956}
3957
3958
3959/*! Writes a start element with \a name, prefixed for the specified
3960 \a namespaceUri. If the namespace has not been declared yet,
3961 QXmlStreamWriter will generate a namespace declaration for
3962 it. Subsequent calls to writeAttribute() will add attributes to this
3963 element.
3964
3965 \sa writeNamespace(), writeEndElement(), writeEmptyElement()
3966 */
3967void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name)
3968{
3969 Q_D(QXmlStreamWriter);
3970 Q_ASSERT(!name.contains(QLatin1Char(':')));
3971 d->writeStartElement(namespaceUri, name);
3972}
3973
3974void QXmlStreamWriterPrivate::writeStartElement(const QString &namespaceUri, const QString &name)
3975{
3976 if (!finishStartElement(contents: false) && autoFormatting)
3977 indent(level: tagStack.size());
3978
3979 Tag &tag = tagStack_push();
3980 tag.name = addToStringStorage(s: name);
3981 tag.namespaceDeclaration = findNamespace(namespaceUri);
3982 write(s: "<");
3983 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
3984 write(s: tag.namespaceDeclaration.prefix);
3985 write(s: ":");
3986 }
3987 write(s: tag.name);
3988 inStartElement = lastWasStartElement = true;
3989
3990 for (int i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
3991 writeNamespaceDeclaration(namespaceDeclaration: namespaceDeclarations[i]);
3992 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
3993}
3994
3995#ifndef QT_NO_XMLSTREAMREADER
3996/*! Writes the current state of the \a reader. All possible valid
3997 states are supported.
3998
3999 The purpose of this function is to support chained processing of XML data.
4000
4001 \sa QXmlStreamReader::tokenType()
4002 */
4003void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
4004{
4005 switch (reader.tokenType()) {
4006 case QXmlStreamReader::NoToken:
4007 break;
4008 case QXmlStreamReader::StartDocument:
4009 writeStartDocument();
4010 break;
4011 case QXmlStreamReader::EndDocument:
4012 writeEndDocument();
4013 break;
4014 case QXmlStreamReader::StartElement: {
4015 writeStartElement(namespaceUri: reader.namespaceUri().toString(), name: reader.name().toString());
4016 QXmlStreamNamespaceDeclarations namespaceDeclarations = reader.namespaceDeclarations();
4017 for (int i = 0; i < namespaceDeclarations.size(); ++i) {
4018 const QXmlStreamNamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(i);
4019 writeNamespace(namespaceUri: namespaceDeclaration.namespaceUri().toString(),
4020 prefix: namespaceDeclaration.prefix().toString());
4021 }
4022 writeAttributes(attributes: reader.attributes());
4023 } break;
4024 case QXmlStreamReader::EndElement:
4025 writeEndElement();
4026 break;
4027 case QXmlStreamReader::Characters:
4028 if (reader.isCDATA())
4029 writeCDATA(text: reader.text().toString());
4030 else
4031 writeCharacters(text: reader.text().toString());
4032 break;
4033 case QXmlStreamReader::Comment:
4034 writeComment(text: reader.text().toString());
4035 break;
4036 case QXmlStreamReader::DTD:
4037 writeDTD(dtd: reader.text().toString());
4038 break;
4039 case QXmlStreamReader::EntityReference:
4040 writeEntityReference(name: reader.name().toString());
4041 break;
4042 case QXmlStreamReader::ProcessingInstruction:
4043 writeProcessingInstruction(target: reader.processingInstructionTarget().toString(),
4044 data: reader.processingInstructionData().toString());
4045 break;
4046 default:
4047 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4048 qWarning(msg: "QXmlStreamWriter: writeCurrentToken() with invalid state.");
4049 break;
4050 }
4051}
4052
4053/*!
4054 \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
4055 \since 4.5
4056
4057 Returns \c true if this QXmlStreamAttributes has an attribute whose
4058 qualified name is \a qualifiedName; otherwise returns \c false.
4059
4060 Note that this is not namespace aware. For instance, if this
4061 QXmlStreamAttributes contains an attribute whose lexical name is "xlink:href"
4062 this doesn't tell that an attribute named \c href in the XLink namespace is
4063 present, since the \c xlink prefix can be bound to any namespace. Use the
4064 overload that takes a namespace URI and a local name as parameter, for
4065 namespace aware code.
4066*/
4067
4068/*!
4069 \fn bool QXmlStreamAttributes::hasAttribute(QLatin1String qualifiedName) const
4070 \overload
4071 \since 4.5
4072*/
4073
4074/*!
4075 \fn bool QXmlStreamAttributes::hasAttribute(const QString &namespaceUri,
4076 const QString &name) const
4077 \overload
4078 \since 4.5
4079
4080 Returns \c true if this QXmlStreamAttributes has an attribute whose
4081 namespace URI and name correspond to \a namespaceUri and \a name;
4082 otherwise returns \c false.
4083*/
4084
4085#endif // QT_NO_XMLSTREAMREADER
4086#endif // QT_NO_XMLSTREAMWRITER
4087
4088QT_END_NAMESPACE
4089
4090#endif // QT_NO_XMLSTREAM
4091

source code of qtbase/src/corelib/serialization/qxmlstream.cpp