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