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