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 ¬ationDeclaration = 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("<"));
3156 break;
3157 case '>':
3158 escaped.append(QLatin1String(">"));
3159 break;
3160 case '&':
3161 escaped.append(QLatin1String("&"));
3162 break;
3163 case '\"':
3164 escaped.append(QLatin1String("""));
3165 break;
3166 case '\t':
3167 if (escapeWhitespace)
3168 escaped.append(QLatin1String("	"));
3169 else
3170 escaped += c;
3171 break;
3172 case '\n':
3173 if (escapeWhitespace)
3174 escaped.append(QLatin1String(" "));
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(" "));
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 "<", "&, and """. To avoid the forbidden sequence
3626 "]]>", ">" is also escaped as ">".
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