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 QtXml 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 "qglobal.h"
41 
42 // Disable warning about use of deprecated QXmlStreamLocator in QScopedPointer<>
43 QT_WARNING_DISABLE_MSVC(4996)
44 
45 #include "qxml.h"
46 #include "qxml_p.h"
47 #if QT_CONFIG(textcodec)
48 #include "qtextcodec.h"
49 #endif
50 #include "qbuffer.h"
51 #if QT_CONFIG(regularexpression)
52 #include "qregularexpression.h"
53 #endif
54 #include "qmap.h"
55 #include "qhash.h"
56 #include "qstack.h"
57 #include <qdebug.h>
58 
59 #if QT_DEPRECATED_SINCE(5, 15)
60 
61 #ifdef Q_CC_BOR // borland 6 finds bogus warnings when building this file in uic3
62 #    pragma warn -8080
63 #endif
64 
65 //#define QT_QXML_DEBUG
66 
67 // Error strings for the XML reader
68 #define XMLERR_OK                         QT_TRANSLATE_NOOP("QXml", "no error occurred")
69 #define XMLERR_ERRORBYCONSUMER            QT_TRANSLATE_NOOP("QXml", "error triggered by consumer")
70 #define XMLERR_UNEXPECTEDEOF              QT_TRANSLATE_NOOP("QXml", "unexpected end of file")
71 #define XMLERR_MORETHANONEDOCTYPE         QT_TRANSLATE_NOOP("QXml", "more than one document type definition")
72 #define XMLERR_ERRORPARSINGELEMENT        QT_TRANSLATE_NOOP("QXml", "error occurred while parsing element")
73 #define XMLERR_TAGMISMATCH                QT_TRANSLATE_NOOP("QXml", "tag mismatch")
74 #define XMLERR_ERRORPARSINGCONTENT        QT_TRANSLATE_NOOP("QXml", "error occurred while parsing content")
75 #define XMLERR_UNEXPECTEDCHARACTER        QT_TRANSLATE_NOOP("QXml", "unexpected character")
76 #define XMLERR_INVALIDNAMEFORPI           QT_TRANSLATE_NOOP("QXml", "invalid name for processing instruction")
77 #define XMLERR_VERSIONEXPECTED            QT_TRANSLATE_NOOP("QXml", "version expected while reading the XML declaration")
78 #define XMLERR_WRONGVALUEFORSDECL         QT_TRANSLATE_NOOP("QXml", "wrong value for standalone declaration")
79 #define XMLERR_EDECLORSDDECLEXPECTED      QT_TRANSLATE_NOOP("QXml", "encoding declaration or standalone declaration expected while reading the XML declaration")
80 #define XMLERR_SDDECLEXPECTED             QT_TRANSLATE_NOOP("QXml", "standalone declaration expected while reading the XML declaration")
81 #define XMLERR_ERRORPARSINGDOCTYPE        QT_TRANSLATE_NOOP("QXml", "error occurred while parsing document type definition")
82 #define XMLERR_LETTEREXPECTED             QT_TRANSLATE_NOOP("QXml", "letter is expected")
83 #define XMLERR_ERRORPARSINGCOMMENT        QT_TRANSLATE_NOOP("QXml", "error occurred while parsing comment")
84 #define XMLERR_ERRORPARSINGREFERENCE      QT_TRANSLATE_NOOP("QXml", "error occurred while parsing reference")
85 #define XMLERR_INTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "internal general entity reference not allowed in DTD")
86 #define XMLERR_EXTERNALGENERALENTITYINAV  QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in attribute value")
87 #define XMLERR_EXTERNALGENERALENTITYINDTD QT_TRANSLATE_NOOP("QXml", "external parsed general entity reference not allowed in DTD")
88 #define XMLERR_UNPARSEDENTITYREFERENCE    QT_TRANSLATE_NOOP("QXml", "unparsed entity reference in wrong context")
89 #define XMLERR_RECURSIVEENTITIES          QT_TRANSLATE_NOOP("QXml", "recursive entities")
90 #define XMLERR_ERRORINTEXTDECL            QT_TRANSLATE_NOOP("QXml", "error in the text declaration of an external entity")
91 
92 QT_BEGIN_NAMESPACE
93 
94 namespace {
95 
96 // work around missing std::stack::clear()
97 template <typename Container>
clear(Container & c)98 void clear(Container &c) { c = Container(); }
99 
100 }
101 
102 // the constants for the lookup table
103 static const signed char cltWS      =  0; // white space
104 static const signed char cltPer     =  1; // %
105 static const signed char cltAmp     =  2; // &
106 static const signed char cltGt      =  3; // >
107 static const signed char cltLt      =  4; // <
108 static const signed char cltSlash   =  5; // /
109 static const signed char cltQm      =  6; // ?
110 static const signed char cltEm      =  7; // !
111 static const signed char cltDash    =  8; // -
112 static const signed char cltCB      =  9; // ]
113 static const signed char cltOB      = 10; // [
114 static const signed char cltEq      = 11; // =
115 static const signed char cltDq      = 12; // "
116 static const signed char cltSq      = 13; // '
117 static const signed char cltUnknown = 14;
118 
119 // character lookup table
120 static const signed char charLookupTable[256]={
121     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07
122     cltUnknown, // 0x08
123     cltWS,      // 0x09 \t
124     cltWS,      // 0x0A \n
125     cltUnknown, // 0x0B
126     cltUnknown, // 0x0C
127     cltWS,      // 0x0D \r
128     cltUnknown, // 0x0E
129     cltUnknown, // 0x0F
130     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16
131     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F
132     cltWS,      // 0x20 Space
133     cltEm,      // 0x21 !
134     cltDq,      // 0x22 "
135     cltUnknown, // 0x23
136     cltUnknown, // 0x24
137     cltPer,     // 0x25 %
138     cltAmp,     // 0x26 &
139     cltSq,      // 0x27 '
140     cltUnknown, // 0x28
141     cltUnknown, // 0x29
142     cltUnknown, // 0x2A
143     cltUnknown, // 0x2B
144     cltUnknown, // 0x2C
145     cltDash,    // 0x2D -
146     cltUnknown, // 0x2E
147     cltSlash,   // 0x2F /
148     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37
149     cltUnknown, // 0x38
150     cltUnknown, // 0x39
151     cltUnknown, // 0x3A
152     cltUnknown, // 0x3B
153     cltLt,      // 0x3C <
154     cltEq,      // 0x3D =
155     cltGt,      // 0x3E >
156     cltQm,      // 0x3F ?
157     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47
158     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F
159     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57
160     cltUnknown, // 0x58
161     cltUnknown, // 0x59
162     cltUnknown, // 0x5A
163     cltOB,      // 0x5B [
164     cltUnknown, // 0x5C
165     cltCB,      // 0x5D]
166     cltUnknown, // 0x5E
167     cltUnknown, // 0x5F
168     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67
169     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F
170     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77
171     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F
172     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87
173     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F
174     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97
175     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F
176     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7
177     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF
178     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7
179     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF
180     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7
181     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF
182     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7
183     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF
184     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7
185     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF
186     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7
187     cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown  // 0xF8 - 0xFF
188 };
189 
190 //
191 // local helper functions
192 //
193 
194 /*
195   This function strips the TextDecl [77] ("<?xml ...?>") from the string \a
196   str. The stripped version is stored in \a str. If this function finds an
197   invalid TextDecl, it returns \c false, otherwise true.
198 
199   This function is used for external entities since those can include an
200   TextDecl that must be stripped before inserting the entity.
201 */
stripTextDecl(QString & str)202 static bool stripTextDecl(QString& str)
203 {
204     QLatin1String textDeclStart("<?xml");
205     if (str.startsWith(textDeclStart)) {
206 #if QT_CONFIG(regularexpression)
207         QRegularExpression textDecl(QString::fromLatin1(
208             "^<\\?xml\\s+"
209             "(version\\s*=\\s*((['\"])[-a-zA-Z0-9_.:]+\\3))?"
210             "\\s*"
211             "(encoding\\s*=\\s*((['\"])[A-Za-z][-a-zA-Z0-9_.]*\\6))?"
212             "\\s*\\?>"
213         ));
214         QString strTmp = str.replace(textDecl, QLatin1String(""));
215         if (strTmp.length() != str.length())
216             return false; // external entity has wrong TextDecl
217         str = strTmp;
218 #else
219         return false;
220 #endif
221     }
222     return true;
223 }
224 
225 
226 class QXmlAttributesPrivate
227 {
228 };
229 
230 /* \class QXmlInputSourcePrivate
231     \internal
232 
233   There's a slight misdesign in this class that can
234   be worth to keep in mind: the `str' member is
235   a buffer which QXmlInputSource::next() returns from,
236   and which is populated from the input device or input
237   stream. However, when the input is a QString(the user called
238   QXmlInputSource::setData()), `str' has two roles: it's the
239   buffer, but also the source. This /seems/ to be no problem
240   because in the case of having no device or stream, the QString
241   is read in one go.
242  */
243 class QXmlInputSourcePrivate
244 {
245 public:
246     QIODevice *inputDevice;
247     QTextStream *inputStream;
248 
249     QString str;
250     const QChar *unicode;
251     int pos;
252     int length;
253     bool nextReturnedEndOfData;
254 #if QT_CONFIG(textcodec)
255     QTextDecoder *encMapper;
256 #endif
257 
258     QByteArray encodingDeclBytes;
259     QString encodingDeclChars;
260     bool lookingForEncodingDecl;
261 };
262 class QXmlParseExceptionPrivate
263 {
264 public:
QXmlParseExceptionPrivate()265     QXmlParseExceptionPrivate()
266         : column(-1), line(-1)
267     {
268     }
QXmlParseExceptionPrivate(const QXmlParseExceptionPrivate & other)269     QXmlParseExceptionPrivate(const QXmlParseExceptionPrivate &other)
270         : msg(other.msg), column(other.column), line(other.line),
271           pub(other.pub), sys(other.sys)
272     {
273     }
274 
275     QString msg;
276     int column;
277     int line;
278     QString pub;
279     QString sys;
280 
281 };
282 
283 class QXmlLocatorPrivate
284 {
285 };
286 
287 class QXmlDefaultHandlerPrivate
288 {
289 };
290 
291 /*!
292     \class QXmlParseException
293     \obsolete
294     \reentrant
295     \brief The QXmlParseException class is used to report errors with
296     the QXmlErrorHandler interface.
297 
298     \inmodule QtXml
299     \ingroup xml-tools
300 
301     The XML subsystem constructs an instance of this class when it
302     detects an error. You can retrieve the place where the error
303     occurred using systemId(), publicId(), lineNumber() and
304     columnNumber(), along with the error message(). The possible error
305     messages are:
306 
307 
308     \list
309         \li "no error occurred"
310         \li "error triggered by consumer"
311         \li "unexpected end of file"
312         \li "more than one document type definition"
313         \li "error occurred while parsing element"
314         \li "tag mismatch"
315         \li "error occurred while parsing content"
316         \li "unexpected character"
317         \li "invalid name for processing instruction"
318         \li "version expected while reading the XML declaration"
319         \li "wrong value for standalone declaration"
320         \li "encoding declaration or standalone declaration expected while reading the XML declaration"
321         \li "standalone declaration expected while reading the XML declaration"
322         \li "error occurred while parsing document type definition"
323         \li "letter is expected"
324         \li "error occurred while parsing comment"
325         \li "error occurred while parsing reference"
326         \li "internal general entity reference not allowed in DTD"
327         \li "external parsed general entity reference not allowed in attribute value"
328         \li "external parsed general entity reference not allowed in DTD"
329         \li "unparsed entity reference n wrong context"
330         \li "recursive entities"
331         \li "error in the text declaration of an external entity"
332     \endlist
333 
334     Note that, if you want to display these error messages to your
335     application's users, they will be displayed in English unless
336     they are explicitly translated.
337 
338     \sa QXmlErrorHandler, QXmlReader
339 */
340 
341 /*!
342     Constructs a parse exception with the error string \a name for
343     column \a c and line \a l for the public identifier \a p and the
344     system identifier \a s.
345 */
346 
QXmlParseException(const QString & name,int c,int l,const QString & p,const QString & s)347 QXmlParseException::QXmlParseException(const QString& name, int c, int l,
348                                        const QString& p, const QString& s)
349     : d(new QXmlParseExceptionPrivate)
350 {
351     d->msg = name;
352     d->column = c;
353     d->line = l;
354     d->pub = p;
355     d->sys = s;
356 }
357 
358 /*!
359     Creates a copy of \a other.
360 */
QXmlParseException(const QXmlParseException & other)361 QXmlParseException::QXmlParseException(const QXmlParseException& other) :
362      d(new QXmlParseExceptionPrivate(*other.d))
363 {
364 
365 }
366 
367 /*!
368     Destroys the QXmlParseException.
369 */
~QXmlParseException()370 QXmlParseException::~QXmlParseException()
371 {
372 }
373 
374 /*!
375     Returns the error message.
376 */
message() const377 QString QXmlParseException::message() const
378 {
379     return d->msg;
380 }
381 /*!
382     Returns the column number where the error occurred.
383 */
columnNumber() const384 int QXmlParseException::columnNumber() const
385 {
386     return d->column;
387 }
388 /*!
389     Returns the line number where the error occurred.
390 */
lineNumber() const391 int QXmlParseException::lineNumber() const
392 {
393     return d->line;
394 }
395 /*!
396     Returns the public identifier where the error occurred.
397 */
publicId() const398 QString QXmlParseException::publicId() const
399 {
400     return d->pub;
401 }
402 /*!
403     Returns the system identifier where the error occurred.
404 */
systemId() const405 QString QXmlParseException::systemId() const
406 {
407     return d->sys;
408 }
409 
410 
411 /*!
412     \class QXmlLocator
413     \obsolete
414     \reentrant
415     \brief The QXmlLocator class provides the XML handler classes with
416     information about the parsing position within a file.
417 
418     \inmodule QtXml
419     \ingroup xml-tools
420 
421     The reader reports a QXmlLocator to the content handler before it
422     starts to parse the document. This is done with the
423     QXmlContentHandler::setDocumentLocator() function. The handler
424     classes can now use this locator to get the position (lineNumber()
425     and columnNumber()) that the reader has reached.
426 */
427 
428 /*!
429     Constructor.
430 */
QXmlLocator()431 QXmlLocator::QXmlLocator()
432 {
433 }
434 
435 /*!
436     Destructor.
437 */
~QXmlLocator()438 QXmlLocator::~QXmlLocator()
439 {
440 }
441 
442 /*!
443     \fn int QXmlLocator::columnNumber() const
444 
445     Returns the column number (starting at 1) or -1 if there is no
446     column number available.
447 */
448 
449 /*!
450     \fn int QXmlLocator::lineNumber() const
451 
452     Returns the line number (starting at 1) or -1 if there is no line
453     number available.
454 */
455 
456 QT_WARNING_PUSH
457 QT_WARNING_DISABLE_DEPRECATED
458 
459 class QXmlSimpleReaderLocator : public QXmlLocator
460 {
461 public:
QXmlSimpleReaderLocator(QXmlSimpleReader * parent)462     QXmlSimpleReaderLocator(QXmlSimpleReader* parent)
463     {
464         reader = parent;
465     }
~QXmlSimpleReaderLocator()466     ~QXmlSimpleReaderLocator()
467     {
468     }
469 
columnNumber() const470     int columnNumber() const override
471     {
472         return (reader->d_ptr->columnNr == -1 ? -1 : reader->d_ptr->columnNr + 1);
473     }
lineNumber() const474     int lineNumber() const override
475     {
476         return (reader->d_ptr->lineNr == -1 ? -1 : reader->d_ptr->lineNr + 1);
477     }
478 //    QString getPublicId()
479 //    QString getSystemId()
480 
481 private:
482     QXmlSimpleReader *reader;
483 };
484 
485 /*********************************************
486  *
487  * QXmlNamespaceSupport
488  *
489  *********************************************/
490 
491 typedef QMap<QString, QString> NamespaceMap;
492 
493 class QXmlNamespaceSupportPrivate
494 {
495 public:
QXmlNamespaceSupportPrivate()496     QXmlNamespaceSupportPrivate()
497     {
498         ns.insert(QLatin1String("xml"), QLatin1String("http://www.w3.org/XML/1998/namespace")); // the XML namespace
499     }
500 
~QXmlNamespaceSupportPrivate()501     ~QXmlNamespaceSupportPrivate()
502     {
503     }
504 
505     QStack<NamespaceMap> nsStack;
506     NamespaceMap ns;
507 };
508 
509 /*!
510     \class QXmlNamespaceSupport
511     \obsolete
512     \since 4.4
513     \reentrant
514     \brief The QXmlNamespaceSupport class is a helper class for XML
515     readers which want to include namespace support.
516 
517     \inmodule QtXml
518     \ingroup xml-tools
519 
520     You can set the prefix for the current namespace with setPrefix(),
521     and get the list of current prefixes (or those for a given URI)
522     with prefixes(). The namespace URI is available from uri(). Use
523     pushContext() to start a new namespace context, and popContext()
524     to return to the previous namespace context. Use splitName() or
525     processName() to split a name into its prefix and local name.
526 */
527 
528 /*!
529     Constructs a QXmlNamespaceSupport.
530 */
QXmlNamespaceSupport()531 QXmlNamespaceSupport::QXmlNamespaceSupport()
532 {
533     d = new QXmlNamespaceSupportPrivate;
534 }
535 
536 /*!
537     Destroys a QXmlNamespaceSupport.
538 */
~QXmlNamespaceSupport()539 QXmlNamespaceSupport::~QXmlNamespaceSupport()
540 {
541     delete d;
542 }
543 
544 /*!
545     This function declares a prefix \a pre in the current namespace
546     context to be the namespace URI \a uri. The prefix remains in
547     force until this context is popped, unless it is shadowed in a
548     descendant context.
549 
550     Note that there is an asymmetry in this library. prefix() does not
551     return the default "" prefix, even if you have declared one; to
552     check for a default prefix, you must look it up explicitly using
553     uri(). This asymmetry exists to make it easier to look up prefixes
554     for attribute names, where the default prefix is not allowed.
555 */
setPrefix(const QString & pre,const QString & uri)556 void QXmlNamespaceSupport::setPrefix(const QString& pre, const QString& uri)
557 {
558     if(pre.isNull()) {
559         d->ns.insert(QLatin1String(""), uri);
560     } else {
561         d->ns.insert(pre, uri);
562     }
563 }
564 
565 /*!
566     Returns one of the prefixes mapped to the namespace URI \a uri.
567 
568     If more than one prefix is currently mapped to the same URI, this
569     function makes an arbitrary selection; if you want all of the
570     prefixes, use prefixes() instead.
571 
572     Note: to check for a default prefix, use the uri() function with
573     an argument of "".
574 */
prefix(const QString & uri) const575 QString QXmlNamespaceSupport::prefix(const QString& uri) const
576 {
577     NamespaceMap::const_iterator itc, it = d->ns.constBegin();
578     while ((itc=it) != d->ns.constEnd()) {
579         ++it;
580         if (*itc == uri && !itc.key().isEmpty())
581             return itc.key();
582     }
583     return QLatin1String("");
584 }
585 
586 /*!
587     Looks up the prefix \a prefix in the current context and returns
588     the currently-mapped namespace URI. Use the empty string ("") for
589     the default namespace.
590 */
uri(const QString & prefix) const591 QString QXmlNamespaceSupport::uri(const QString& prefix) const
592 {
593     return d->ns[prefix];
594 }
595 
596 /*!
597     Splits the name \a qname at the ':' and returns the prefix in \a
598     prefix and the local name in \a localname.
599 
600     \sa processName()
601 */
splitName(const QString & qname,QString & prefix,QString & localname) const602 void QXmlNamespaceSupport::splitName(const QString& qname, QString& prefix,
603                                      QString& localname) const
604 {
605     int pos = qname.indexOf(QLatin1Char(':'));
606     if (pos == -1)
607         pos = qname.size();
608 
609     prefix = qname.left(pos);
610     localname = qname.mid(pos+1);
611 }
612 
613 /*!
614     Processes a raw XML 1.0 name in the current context by removing
615     the prefix and looking it up among the prefixes currently
616     declared.
617 
618     \a qname is the raw XML 1.0 name to be processed. \a isAttribute
619     is true if the name is an attribute name.
620 
621     This function stores the namespace URI in \a nsuri (which will be
622     set to an empty string if the raw name has an undeclared prefix),
623     and stores the local name (without prefix) in \a localname (which
624     will be set to an empty string if no namespace is in use).
625 
626     Note that attribute names are processed differently than element
627     names: an unprefixed element name gets the default namespace (if
628     any), while an unprefixed attribute name does not.
629 */
processName(const QString & qname,bool isAttribute,QString & nsuri,QString & localname) const630 void QXmlNamespaceSupport::processName(const QString& qname,
631         bool isAttribute,
632         QString& nsuri, QString& localname) const
633 {
634     int len = qname.size();
635     const QChar *data = qname.constData();
636     for (int pos = 0; pos < len; ++pos) {
637         if (data[pos] == QLatin1Char(':')) {
638             nsuri = uri(qname.left(pos));
639             localname = qname.mid(pos + 1);
640             return;
641         }
642     }
643 
644     // there was no ':'
645     nsuri.clear();
646     // attributes don't take default namespace
647     if (!isAttribute && !d->ns.isEmpty()) {
648         /*
649             We want to access d->ns.value(""), but as an optimization
650             we use the fact that "" compares less than any other
651             string, so it's either first in the map or not there.
652         */
653         NamespaceMap::const_iterator first = d->ns.constBegin();
654         if (first.key().isEmpty())
655             nsuri = first.value(); // get default namespace
656     }
657     localname = qname;
658 }
659 
660 /*!
661     Returns a list of all the prefixes currently declared.
662 
663     If there is a default prefix, this function does not return it in
664     the list; check for the default prefix using uri() with an
665     argument of "".
666 */
prefixes() const667 QStringList QXmlNamespaceSupport::prefixes() const
668 {
669     QStringList list;
670 
671     NamespaceMap::const_iterator itc, it = d->ns.constBegin();
672     while ((itc=it) != d->ns.constEnd()) {
673         ++it;
674         if (!itc.key().isEmpty())
675             list.append(itc.key());
676     }
677     return list;
678 }
679 
680 /*!
681     \overload
682 
683     Returns a list of all prefixes currently declared for the
684     namespace URI \a uri.
685 
686     The "xml:" prefix is included. If you only want one prefix that is
687     mapped to the namespace URI, and you don't care which one you get,
688     use the prefix() function instead.
689 
690     Note: The empty (default) prefix is never included in this list;
691     to check for the presence of a default namespace, call uri() with
692     "" as the argument.
693 */
prefixes(const QString & uri) const694 QStringList QXmlNamespaceSupport::prefixes(const QString& uri) const
695 {
696     QStringList list;
697 
698     NamespaceMap::const_iterator itc, it = d->ns.constBegin();
699     while ((itc=it) != d->ns.constEnd()) {
700         ++it;
701         if (*itc == uri && !itc.key().isEmpty())
702             list.append(itc.key());
703     }
704     return list;
705 }
706 
707 /*!
708     Starts a new namespace context.
709 
710     Normally, you should push a new context at the beginning of each
711     XML element: the new context automatically inherits the
712     declarations of its parent context, and it also keeps track of
713     which declarations were made within this context.
714 
715     \sa popContext()
716 */
pushContext()717 void QXmlNamespaceSupport::pushContext()
718 {
719     d->nsStack.push(d->ns);
720 }
721 
722 /*!
723     Reverts to the previous namespace context.
724 
725     Normally, you should pop the context at the end of each XML
726     element. After popping the context, all namespace prefix mappings
727     that were previously in force are restored.
728 
729     \sa pushContext()
730 */
popContext()731 void QXmlNamespaceSupport::popContext()
732 {
733     d->ns.clear();
734     if(!d->nsStack.isEmpty())
735         d->ns = d->nsStack.pop();
736 }
737 
738 /*!
739     Resets this namespace support object ready for reuse.
740 */
reset()741 void QXmlNamespaceSupport::reset()
742 {
743     QXmlNamespaceSupportPrivate *newD = new QXmlNamespaceSupportPrivate;
744     delete d;
745     d = newD;
746 }
747 
748 
749 
750 /*********************************************
751  *
752  * QXmlAttributes
753  *
754  *********************************************/
755 
756 /*!
757     \class QXmlAttributes
758     \obsolete
759     \reentrant
760     \brief The QXmlAttributes class provides XML attributes.
761 
762     \inmodule QtXml
763     \ingroup xml-tools
764 
765     If attributes are reported by QXmlContentHandler::startElement()
766     this class is used to pass the attribute values.
767 
768     Use index() to locate the position of an attribute in the list,
769     count() to retrieve the number of attributes, and clear() to
770     remove the attributes. New attributes can be added with append().
771     Use type() to get an attribute's type and value() to get its
772     value. The attribute's name is available from localName() or
773     qName(), and its namespace URI from uri().
774 
775 */
776 
777 /*!
778     \fn QXmlAttributes::QXmlAttributes()
779 
780     Constructs an empty attribute list.
781 */
QXmlAttributes()782 QXmlAttributes::QXmlAttributes()
783 {
784     // ### In Qt 5.0, this function was inlined and d was not initialized
785     // The member cannot be used until Qt 6.0
786     Q_UNUSED(d);
787 }
788 
789 /*!
790     \fn QXmlAttributes::~QXmlAttributes()
791 
792     Destroys the attributes object.
793 */
~QXmlAttributes()794 QXmlAttributes::~QXmlAttributes()
795 {
796 }
797 
798 /*!
799   \fn void QXmlAttributes::swap(QXmlAttributes &other)
800 
801   Swaps \c this with \a other.
802  */
803 
804 /*!
805     Looks up the index of an attribute by the qualified name \a qName.
806 
807     Returns the index of the attribute or -1 if it wasn't found.
808 */
index(const QString & qName) const809 int QXmlAttributes::index(const QString& qName) const
810 {
811     for (int i = 0; i < attList.size(); ++i) {
812         if (attList.at(i).qname == qName)
813             return i;
814     }
815     return -1;
816 }
817 
818 /*! \overload
819   */
index(QLatin1String qName) const820 int QXmlAttributes::index(QLatin1String qName) const
821 {
822     for (int i = 0; i < attList.size(); ++i) {
823         if (attList.at(i).qname == qName)
824             return i;
825     }
826     return -1;
827 }
828 
829 /*!
830     \overload
831 
832     Looks up the index of an attribute by a namespace name.
833 
834     \a uri specifies the namespace URI, or an empty string if the name
835     has no namespace URI. \a localPart specifies the attribute's local
836     name.
837 
838     Returns the index of the attribute, or -1 if it wasn't found.
839 */
index(const QString & uri,const QString & localPart) const840 int QXmlAttributes::index(const QString& uri, const QString& localPart) const
841 {
842     for (int i = 0; i < attList.size(); ++i) {
843         const Attribute &att = attList.at(i);
844         if (att.uri == uri && att.localname == localPart)
845             return i;
846     }
847     return -1;
848 }
849 
850 /*!
851     Returns the number of attributes in the list.
852 
853     \sa count()
854 */
length() const855 int QXmlAttributes::length() const
856 {
857     return attList.count();
858 }
859 
860 /*!
861     \fn int QXmlAttributes::count() const
862 
863     Returns the number of attributes in the list. This function is
864     equivalent to length().
865 */
866 
867 /*!
868     Looks up an attribute's local name for the attribute at position
869     \a index. If no namespace processing is done, the local name is
870     an empty string.
871 */
localName(int index) const872 QString QXmlAttributes::localName(int index) const
873 {
874     return attList.at(index).localname;
875 }
876 
877 /*!
878     Looks up an attribute's XML 1.0 qualified name for the attribute
879     at position \a index.
880 */
qName(int index) const881 QString QXmlAttributes::qName(int index) const
882 {
883     return attList.at(index).qname;
884 }
885 
886 /*!
887     Looks up an attribute's namespace URI for the attribute at
888     position \a index. If no namespace processing is done or if the
889     attribute has no namespace, the namespace URI is an empty string.
890 */
uri(int index) const891 QString QXmlAttributes::uri(int index) const
892 {
893     return attList.at(index).uri;
894 }
895 
896 /*!
897     Looks up an attribute's type for the attribute at position \a
898     index.
899 
900     Currently only "CDATA" is returned.
901 */
type(int) const902 QString QXmlAttributes::type(int) const
903 {
904     return QLatin1String("CDATA");
905 }
906 
907 /*!
908     \overload
909 
910     Looks up an attribute's type for the qualified name \a qName.
911 
912     Currently only "CDATA" is returned.
913 */
type(const QString &) const914 QString QXmlAttributes::type(const QString&) const
915 {
916     return QLatin1String("CDATA");
917 }
918 
919 /*!
920     \overload
921 
922     Looks up an attribute's type by namespace name.
923 
924     \a uri specifies the namespace URI and \a localName specifies the
925     local name. If the name has no namespace URI, use an empty string
926     for \a uri.
927 
928     Currently only "CDATA" is returned.
929 */
type(const QString &,const QString &) const930 QString QXmlAttributes::type(const QString&, const QString&) const
931 {
932     return QLatin1String("CDATA");
933 }
934 
935 /*!
936     Returns an attribute's value for the attribute at position \a
937     index. The index must be a valid position
938     (i.e., 0 <= \a index < count()).
939 */
value(int index) const940 QString QXmlAttributes::value(int index) const
941 {
942     return attList.at(index).value;
943 }
944 
945 /*!
946     \overload
947 
948     Returns an attribute's value for the qualified name \a qName, or an
949     empty string if no attribute exists for the name given.
950 */
value(const QString & qName) const951 QString QXmlAttributes::value(const QString& qName) const
952 {
953     int i = index(qName);
954     if (i == -1)
955         return QString();
956     return attList.at(i).value;
957 }
958 
959 /*!
960     \overload
961 
962     Returns an attribute's value for the qualified name \a qName, or an
963     empty string if no attribute exists for the name given.
964 */
value(QLatin1String qName) const965 QString QXmlAttributes::value(QLatin1String qName) const
966 {
967     int i = index(qName);
968     if (i == -1)
969         return QString();
970     return attList.at(i).value;
971 }
972 
973 /*!
974     \overload
975 
976     Returns an attribute's value by namespace name.
977 
978     \a uri specifies the namespace URI, or an empty string if the name
979     has no namespace URI. \a localName specifies the attribute's local
980     name.
981 */
value(const QString & uri,const QString & localName) const982 QString QXmlAttributes::value(const QString& uri, const QString& localName) const
983 {
984     int i = index(uri, localName);
985     if (i == -1)
986         return QString();
987     return attList.at(i).value;
988 }
989 
990 /*!
991     Clears the list of attributes.
992 
993     \sa append()
994 */
clear()995 void QXmlAttributes::clear()
996 {
997     attList.clear();
998 }
999 
1000 /*!
1001     Appends a new attribute entry to the list of attributes. The
1002     qualified name of the attribute is \a qName, the namespace URI is
1003     \a uri and the local name is \a localPart. The value of the
1004     attribute is \a value.
1005 
1006     \sa qName(), uri(), localName(), value()
1007 */
append(const QString & qName,const QString & uri,const QString & localPart,const QString & value)1008 void QXmlAttributes::append(const QString &qName, const QString &uri, const QString &localPart, const QString &value)
1009 {
1010     Attribute att;
1011     att.qname = qName;
1012     att.uri = uri;
1013     att.localname = localPart;
1014     att.value = value;
1015 
1016     attList.append(att);
1017 }
1018 
1019 
1020 /*********************************************
1021  *
1022  * QXmlInputSource
1023  *
1024  *********************************************/
1025 
1026 /*!
1027     \class QXmlInputSource
1028     \obsolete
1029     \reentrant
1030     \brief The QXmlInputSource class provides the input data for the
1031     QXmlReader subclasses.
1032 
1033     \inmodule QtXml
1034     \ingroup xml-tools
1035 
1036     All subclasses of QXmlReader read the input XML document from this
1037     class.
1038 
1039     This class recognizes the encoding of the data by reading the
1040     encoding declaration in the XML file if it finds one, and reading
1041     the data using the corresponding encoding. If it does not find an
1042     encoding declaration, then it assumes that the data is either in
1043     UTF-8 or UTF-16, depending on whether it can find a byte-order
1044     mark.
1045 
1046     There are two ways to populate the input source with data: you can
1047     construct it with a QIODevice* so that the input source reads the
1048     data from that device. Or you can set the data explicitly with one
1049     of the setData() functions.
1050 
1051     Usually you either construct a QXmlInputSource that works on a
1052     QIODevice* or you construct an empty QXmlInputSource and set the
1053     data with setData(). There are only rare occasions where you would
1054     want to mix both methods.
1055 
1056     The QXmlReader subclasses use the next() function to read the
1057     input character by character. If you want to start from the
1058     beginning again, use reset().
1059 
1060     The functions data() and fetchData() are useful if you want to do
1061     something with the data other than parsing, e.g. displaying the
1062     raw XML file. The benefit of using the QXmlInputClass in such
1063     cases is that it tries to use the correct encoding.
1064 
1065     \sa QXmlReader, QXmlSimpleReader
1066 */
1067 
1068 // the following two are guaranteed not to be a character
1069 const ushort QXmlInputSource::EndOfData = 0xfffe;
1070 const ushort QXmlInputSource::EndOfDocument = 0xffff;
1071 
1072 /*
1073     Common part of the constructors.
1074 */
init()1075 void QXmlInputSource::init()
1076 {
1077     d = new QXmlInputSourcePrivate;
1078 
1079     QT_TRY {
1080         d->inputDevice = nullptr;
1081         d->inputStream = nullptr;
1082 
1083         setData(QString());
1084 #if QT_CONFIG(textcodec)
1085         d->encMapper = nullptr;
1086 #endif
1087         d->nextReturnedEndOfData = true; // first call to next() will call fetchData()
1088 
1089         d->encodingDeclBytes.clear();
1090         d->encodingDeclChars.clear();
1091         d->lookingForEncodingDecl = true;
1092     } QT_CATCH(...) {
1093         delete(d);
1094         QT_RETHROW;
1095     }
1096 }
1097 
1098 /*!
1099     Constructs an input source which contains no data.
1100 
1101     \sa setData()
1102 */
QXmlInputSource()1103 QXmlInputSource::QXmlInputSource()
1104 {
1105     init();
1106 }
1107 
1108 /*!
1109     Constructs an input source and gets the data from device \a dev.
1110     If \a dev is not open, it is opened in read-only mode. If \a dev
1111     is 0 or it is not possible to read from the device, the input
1112     source will contain no data.
1113 
1114     \sa setData(), fetchData(), QIODevice
1115 */
QXmlInputSource(QIODevice * dev)1116 QXmlInputSource::QXmlInputSource(QIODevice *dev)
1117 {
1118     init();
1119     d->inputDevice = dev;
1120     if (dev->isOpen())
1121         d->inputDevice->setTextModeEnabled(false);
1122 }
1123 
1124 /*!
1125     Destructor.
1126 */
~QXmlInputSource()1127 QXmlInputSource::~QXmlInputSource()
1128 {
1129     // ### close the input device.
1130 #if QT_CONFIG(textcodec)
1131     delete d->encMapper;
1132 #endif
1133     delete d;
1134 }
1135 
1136 /*!
1137 Returns the next character of the input source. If this function
1138 reaches the end of available data, it returns
1139 QXmlInputSource::EndOfData. If you call next() after that, it
1140 tries to fetch more data by calling fetchData(). If the
1141 fetchData() call results in new data, this function returns the
1142 first character of that data; otherwise it returns
1143 QXmlInputSource::EndOfDocument.
1144 
1145 Readers, such as QXmlSimpleReader, will assume that the end of
1146 the XML document has been reached if the this function returns
1147 QXmlInputSource::EndOfDocument, and will check that the
1148 supplied input is well-formed. Therefore, when reimplementing
1149 this function, it is important to ensure that this behavior is
1150 duplicated.
1151 
1152 \sa reset(), fetchData(), QXmlSimpleReader::parse(),
1153     QXmlSimpleReader::parseContinue()
1154 */
next()1155 QChar QXmlInputSource::next()
1156 {
1157     if (d->pos >= d->length) {
1158         if (d->nextReturnedEndOfData) {
1159             d->nextReturnedEndOfData = false;
1160             fetchData();
1161             if (d->pos >= d->length) {
1162                 return QChar(EndOfDocument);
1163             }
1164             return next();
1165         }
1166         d->nextReturnedEndOfData = true;
1167         return QChar(EndOfData);
1168     }
1169 
1170     // QXmlInputSource has no way to signal encoding errors. The best we can do
1171     // is return EndOfDocument. We do *not* return EndOfData, because the reader
1172     // will then just call this function again to get the next char.
1173     QChar c = d->unicode[d->pos++];
1174     if (c.unicode() == EndOfData)
1175         c = QChar(EndOfDocument);
1176     return c;
1177 }
1178 
1179 /*!
1180     This function sets the position used by next() to the beginning of
1181     the data returned by data(). This is useful if you want to use the
1182     input source for more than one parse.
1183 
1184     \note In the case that the underlying data source is a QIODevice,
1185     the current position in the device is not automatically set to the
1186     start of input. Call QIODevice::seek(0) on the device to do this.
1187 
1188     \sa next()
1189 */
reset()1190 void QXmlInputSource::reset()
1191 {
1192     d->nextReturnedEndOfData = false;
1193     d->pos = 0;
1194 }
1195 
1196 /*!
1197     Returns the data the input source contains or an empty string if the
1198     input source does not contain any data.
1199 
1200     \sa setData(), QXmlInputSource(), fetchData()
1201 */
data() const1202 QString QXmlInputSource::data() const
1203 {
1204     if (d->nextReturnedEndOfData) {
1205         QXmlInputSource *that = const_cast<QXmlInputSource*>(this);
1206         that->d->nextReturnedEndOfData = false;
1207         that->fetchData();
1208     }
1209     return d->str;
1210 }
1211 
1212 /*!
1213     Sets the data of the input source to \a dat.
1214 
1215     If the input source already contains data, this function deletes
1216     that data first.
1217 
1218     \sa data()
1219 */
setData(const QString & dat)1220 void QXmlInputSource::setData(const QString& dat)
1221 {
1222     d->str = dat;
1223     d->unicode = dat.unicode();
1224     d->pos = 0;
1225     d->length = d->str.length();
1226     d->nextReturnedEndOfData = false;
1227 }
1228 
1229 /*!
1230     \overload
1231 
1232     The data \a dat is passed through the correct text-codec, before
1233     it is set.
1234 */
setData(const QByteArray & dat)1235 void QXmlInputSource::setData(const QByteArray& dat)
1236 {
1237     setData(fromRawData(dat));
1238 }
1239 
1240 /*!
1241     This function reads more data from the device that was set during
1242     construction. If the input source already contained data, this
1243     function deletes that data first.
1244 
1245     This object contains no data after a call to this function if the
1246     object was constructed without a device to read data from or if
1247     this function was not able to get more data from the device.
1248 
1249     There are two occasions where a fetch is done implicitly by
1250     another function call: during construction (so that the object
1251     starts out with some initial data where available), and during a
1252     call to next() (if the data had run out).
1253 
1254     You don't normally need to use this function if you use next().
1255 
1256     \sa data(), next(), QXmlInputSource()
1257 */
1258 
fetchData()1259 void QXmlInputSource::fetchData()
1260 {
1261     enum
1262     {
1263         BufferSize = 1024
1264     };
1265 
1266     QByteArray rawData;
1267 
1268     if (d->inputDevice || d->inputStream) {
1269         QIODevice *device = d->inputDevice ? d->inputDevice : d->inputStream->device();
1270 
1271         if (!device) {
1272             if (d->inputStream && d->inputStream->string()) {
1273                 QString *s = d->inputStream->string();
1274                 rawData = QByteArray((const char *) s->constData(), s->size() * sizeof(QChar));
1275             }
1276         } else if (device->isOpen() || device->open(QIODevice::ReadOnly)) {
1277             rawData.resize(BufferSize);
1278             qint64 size = device->read(rawData.data(), BufferSize);
1279             if (size == 0 && device->waitForReadyRead(-1))
1280                 size = device->read(rawData.data(), BufferSize);
1281 
1282             rawData.resize(qMax(qint64(0), size));
1283         }
1284 
1285         /* We do this inside the "if (d->inputDevice ..." scope
1286          * because if we're not using a stream or device, that is,
1287          * the user set a QString manually, we don't want to set
1288          * d->str. */
1289         setData(fromRawData(rawData));
1290     }
1291 }
1292 
1293 #if QT_CONFIG(textcodec)
extractEncodingDecl(const QString & text,bool * needMoreText)1294 static QString extractEncodingDecl(const QString &text, bool *needMoreText)
1295 {
1296     *needMoreText = false;
1297 
1298     int l = text.length();
1299     const QLatin1String snip("<?xml", std::min(l, 5));
1300     if (l > 0 && !text.startsWith(snip))
1301         return QString();
1302 
1303     int endPos = text.indexOf(QLatin1Char('>'));
1304     if (endPos == -1) {
1305         *needMoreText = l < 255; // we won't look forever
1306         return QString();
1307     }
1308 
1309     int pos = text.indexOf(QLatin1String("encoding"));
1310     if (pos == -1 || pos >= endPos)
1311         return QString();
1312 
1313     while (pos < endPos) {
1314         QChar uc = text.at(pos);
1315         if (uc == u'\'' || uc == u'"')
1316             break;
1317         ++pos;
1318     }
1319 
1320     if (pos == endPos)
1321         return QString();
1322 
1323     QString encoding;
1324     ++pos;
1325     while (pos < endPos) {
1326         QChar uc = text.at(pos);
1327         if (uc == u'\'' || uc == u'"')
1328             break;
1329         encoding.append(uc);
1330         ++pos;
1331     }
1332 
1333     return encoding;
1334 }
1335 #endif // textcodec
1336 
1337 /*!
1338     This function reads the XML file from \a data and tries to
1339     recognize the encoding. It converts the raw data \a data into a
1340     QString and returns it. It tries its best to get the correct
1341     encoding for the XML file.
1342 
1343     If \a beginning is true, this function assumes that the data
1344     starts at the beginning of a new XML document and looks for an
1345     encoding declaration. If \a beginning is false, it converts the
1346     raw data using the encoding determined from prior calls.
1347 */
fromRawData(const QByteArray & data,bool beginning)1348 QString QXmlInputSource::fromRawData(const QByteArray &data, bool beginning)
1349 {
1350 #if !QT_CONFIG(textcodec)
1351     Q_UNUSED(beginning);
1352     return QString::fromLatin1(data.constData(), data.size());
1353 #else
1354     if (data.size() == 0)
1355         return QString();
1356     if (beginning) {
1357         delete d->encMapper;
1358         d->encMapper = nullptr;
1359     }
1360 
1361     int mib = 106; // UTF-8
1362 
1363     // This is the initial UTF codec we will read the encoding declaration with
1364     if (d->encMapper == nullptr) {
1365         d->encodingDeclBytes.clear();
1366         d->encodingDeclChars.clear();
1367         d->lookingForEncodingDecl = true;
1368 
1369         // look for byte order mark and read the first 5 characters
1370         if (data.size() >= 4) {
1371             uchar ch1 = data.at(0);
1372             uchar ch2 = data.at(1);
1373             uchar ch3 = data.at(2);
1374             uchar ch4 = data.at(3);
1375 
1376             if ((ch1 == 0 && ch2 == 0 && ch3 == 0xfe && ch4 == 0xff) ||
1377                 (ch1 == 0xff && ch2 == 0xfe && ch3 == 0 && ch4 == 0))
1378                 mib = 1017; // UTF-32 with byte order mark
1379             else if (ch1 == 0x3c && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x00)
1380                 mib = 1019; // UTF-32LE
1381             else if (ch1 == 0x00 && ch2 == 0x00 && ch3 == 0x00 && ch4 == 0x3c)
1382                 mib = 1018; // UTF-32BE
1383         }
1384         if (mib == 106 && data.size() >= 2) {
1385             uchar ch1 = data.at(0);
1386             uchar ch2 = data.at(1);
1387 
1388             if ((ch1 == 0xfe && ch2 == 0xff) || (ch1 == 0xff && ch2 == 0xfe))
1389                 mib = 1015; // UTF-16 with byte order mark
1390             else if (ch1 == 0x3c && ch2 == 0x00)
1391                 mib = 1014; // UTF-16LE
1392             else if (ch1 == 0x00 && ch2 == 0x3c)
1393                 mib = 1013; // UTF-16BE
1394         }
1395 
1396         QTextCodec *codec = QTextCodec::codecForMib(mib);
1397         Q_ASSERT(codec);
1398 
1399         d->encMapper = codec->makeDecoder();
1400     }
1401 
1402     QString input = d->encMapper->toUnicode(data.constData(), data.size());
1403 
1404     if (d->lookingForEncodingDecl) {
1405         d->encodingDeclChars += input;
1406 
1407         bool needMoreText;
1408         QString encoding = extractEncodingDecl(d->encodingDeclChars, &needMoreText);
1409 
1410         if (!encoding.isEmpty()) {
1411             if (QTextCodec *codec = QTextCodec::codecForName(std::move(encoding).toLatin1())) {
1412                 /* If the encoding is the same, we don't have to do toUnicode() all over again. */
1413                 if(codec->mibEnum() != mib) {
1414                     delete d->encMapper;
1415                     d->encMapper = codec->makeDecoder();
1416 
1417                     /* The variable input can potentially be large, so we deallocate
1418                      * it before calling toUnicode() in order to avoid having two
1419                      * large QStrings in memory simultaneously. */
1420                     input.clear();
1421 
1422                     // prime the decoder with the data so far
1423                     d->encMapper->toUnicode(d->encodingDeclBytes.constData(), d->encodingDeclBytes.size());
1424                     // now feed it the new data
1425                     input = d->encMapper->toUnicode(data.constData(), data.size());
1426                 }
1427             }
1428         }
1429 
1430         d->encodingDeclBytes += data;
1431         d->lookingForEncodingDecl = needMoreText;
1432     }
1433 
1434     return input;
1435 #endif
1436 }
1437 
1438 
1439 /*********************************************
1440  *
1441  * QXmlDefaultHandler
1442  *
1443  *********************************************/
1444 
1445 /*!
1446     \class QXmlContentHandler
1447     \obsolete
1448     \reentrant
1449     \brief The QXmlContentHandler class provides an interface to
1450     report the logical content of XML data.
1451 
1452     \inmodule QtXml
1453     \ingroup xml-tools
1454 
1455     If the application needs to be informed of basic parsing events,
1456     it can implement this interface and activate it using
1457     QXmlReader::setContentHandler(). The reader can then report basic
1458     document-related events like the start and end of elements and
1459     character data through this interface.
1460 
1461     The order of events in this interface is very important, and
1462     mirrors the order of information in the document itself. For
1463     example, all of an element's content (character data, processing
1464     instructions, and sub-elements) appears, in order, between the
1465     startElement() event and the corresponding endElement() event.
1466 
1467     The class QXmlDefaultHandler provides a default implementation for
1468     this interface; subclassing from the QXmlDefaultHandler class is
1469     very convenient if you only want to be informed of some parsing
1470     events.
1471 
1472     The startDocument() function is called at the start of the
1473     document, and endDocument() is called at the end. Before parsing
1474     begins setDocumentLocator() is called. For each element
1475     startElement() is called, with endElement() being called at the
1476     end of each element. The characters() function is called with
1477     chunks of character data; ignorableWhitespace() is called with
1478     chunks of whitespace and processingInstruction() is called with
1479     processing instructions. If an entity is skipped skippedEntity()
1480     is called. At the beginning of prefix-URI scopes
1481     startPrefixMapping() is called.
1482 
1483     \sa QXmlDTDHandler, QXmlDeclHandler, QXmlEntityResolver, QXmlErrorHandler,
1484         QXmlLexicalHandler
1485 */
1486 
1487 /*!
1488     \fn QXmlContentHandler::~QXmlContentHandler()
1489 
1490     Destroys the content handler.
1491 */
1492 
1493 /*!
1494     \fn void QXmlContentHandler::setDocumentLocator(QXmlLocator* locator)
1495 
1496     The reader calls this function before it starts parsing the
1497     document. The argument \a locator is a pointer to a QXmlLocator
1498     which allows the application to get the parsing position within
1499     the document.
1500 
1501     Do not destroy the \a locator; it is destroyed when the reader is
1502     destroyed. (Do not use the \a locator after the reader is
1503     destroyed).
1504 */
1505 
1506 /*!
1507     \fn bool QXmlContentHandler::startDocument()
1508 
1509     The reader calls this function when it starts parsing the
1510     document. The reader calls this function just once, after the call
1511     to setDocumentLocator(), and before any other functions in this
1512     class or in the QXmlDTDHandler class are called.
1513 
1514     If this function returns \c false the reader stops parsing and
1515     reports an error. The reader uses the function errorString() to
1516     get the error message.
1517 
1518     \sa endDocument()
1519 */
1520 
1521 /*!
1522     \fn bool QXmlContentHandler::endDocument()
1523 
1524     The reader calls this function after it has finished parsing. It
1525     is called just once, and is the last handler function called. It
1526     is called after the reader has read all input or has abandoned
1527     parsing because of a fatal error.
1528 
1529     If this function returns \c false the reader stops parsing and
1530     reports an error. The reader uses the function errorString() to
1531     get the error message.
1532 
1533     \sa startDocument()
1534 */
1535 
1536 /*!
1537     \fn bool QXmlContentHandler::startPrefixMapping(const QString& prefix, const QString& uri)
1538 
1539     The reader calls this function to signal the begin of a prefix-URI
1540     namespace mapping scope. This information is not necessary for
1541     normal namespace processing since the reader automatically
1542     replaces prefixes for element and attribute names.
1543 
1544     Note that startPrefixMapping() and endPrefixMapping() calls are
1545     not guaranteed to be properly nested relative to each other: all
1546     startPrefixMapping() events occur before the corresponding
1547     startElement() event, and all endPrefixMapping() events occur
1548     after the corresponding endElement() event, but their order is not
1549     otherwise guaranteed.
1550 
1551     The argument \a prefix is the namespace prefix being declared and
1552     the argument \a uri is the namespace URI the prefix is mapped to.
1553 
1554     If this function returns \c false the reader stops parsing and
1555     reports an error. The reader uses the function errorString() to
1556     get the error message.
1557 
1558     \sa endPrefixMapping()
1559 */
1560 
1561 /*!
1562     \fn bool QXmlContentHandler::endPrefixMapping(const QString& prefix)
1563 
1564     The reader calls this function to signal the end of a prefix
1565     mapping for the prefix \a prefix.
1566 
1567     If this function returns \c false the reader stops parsing and
1568     reports an error. The reader uses the function errorString() to
1569     get the error message.
1570 
1571     \sa startPrefixMapping()
1572 */
1573 
1574 /*!
1575     \fn bool QXmlContentHandler::startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts)
1576 
1577     The reader calls this function when it has parsed a start element
1578     tag.
1579 
1580     There is a corresponding endElement() call when the corresponding
1581     end element tag is read. The startElement() and endElement() calls
1582     are always nested correctly. Empty element tags (e.g. \c{<x/>})
1583     cause a startElement() call to be immediately followed by an
1584     endElement() call.
1585 
1586     The attribute list provided only contains attributes with explicit
1587     values. The attribute list contains attributes used for namespace
1588     declaration (i.e. attributes starting with xmlns) only if the
1589     namespace-prefix property of the reader is true.
1590 
1591     The argument \a namespaceURI is the namespace URI, or
1592     an empty string if the element has no namespace URI or if no
1593     namespace processing is done. \a localName is the local name
1594     (without prefix), or an empty string if no namespace processing is
1595     done, \a qName is the qualified name (with prefix) and \a atts are
1596     the attributes attached to the element. If there are no
1597     attributes, \a atts is an empty attributes object.
1598 
1599     If this function returns \c false the reader stops parsing and
1600     reports an error. The reader uses the function errorString() to
1601     get the error message.
1602 
1603     \sa endElement()
1604 */
1605 
1606 /*!
1607     \fn bool QXmlContentHandler::endElement(const QString& namespaceURI, const QString& localName, const QString& qName)
1608 
1609     The reader calls this function when it has parsed an end element
1610     tag with the qualified name \a qName, the local name \a localName
1611     and the namespace URI \a namespaceURI.
1612 
1613     If this function returns \c false the reader stops parsing and
1614     reports an error. The reader uses the function errorString() to
1615     get the error message.
1616 
1617     \sa startElement()
1618 */
1619 
1620 /*!
1621     \fn bool QXmlContentHandler::characters(const QString& ch)
1622 
1623     The reader calls this function when it has parsed a chunk of
1624     character data (either normal character data or character data
1625     inside a CDATA section; if you need to distinguish between those
1626     two types you must use QXmlLexicalHandler::startCDATA() and
1627     QXmlLexicalHandler::endCDATA()). The character data is reported in
1628     \a ch.
1629 
1630     Some readers report whitespace in element content using the
1631     ignorableWhitespace() function rather than using this one.
1632 
1633     A reader may report the character data of an element in more than
1634     one chunk; e.g. a reader might want to report "a\<b" in three
1635     characters() events ("a ", "\<" and " b").
1636 
1637     If this function returns \c false the reader stops parsing and
1638     reports an error. The reader uses the function errorString() to
1639     get the error message.
1640 */
1641 
1642 /*!
1643     \fn bool QXmlContentHandler::ignorableWhitespace(const QString& ch)
1644 
1645     Some readers may use this function to report each chunk of
1646     whitespace in element content. The whitespace is reported in \a ch.
1647 
1648     If this function returns \c false the reader stops parsing and
1649     reports an error. The reader uses the function errorString() to
1650     get the error message.
1651 */
1652 
1653 /*!
1654     \fn bool QXmlContentHandler::processingInstruction(const QString& target, const QString& data)
1655 
1656     The reader calls this function when it has parsed a processing
1657     instruction.
1658 
1659     \a target is the target name of the processing instruction and \a
1660     data is the data in the processing instruction.
1661 
1662     If this function returns \c false the reader stops parsing and
1663     reports an error. The reader uses the function errorString() to
1664     get the error message.
1665 */
1666 
1667 /*!
1668     \fn bool QXmlContentHandler::skippedEntity(const QString& name)
1669 
1670     Some readers may skip entities if they have not seen the
1671     declarations (e.g. because they are in an external DTD). If they
1672     do so they report that they skipped the entity called \a name by
1673     calling this function.
1674 
1675     If this function returns \c false the reader stops parsing and
1676     reports an error. The reader uses the function errorString() to
1677     get the error message.
1678 */
1679 
1680 /*!
1681     \fn QString QXmlContentHandler::errorString() const
1682 
1683     The reader calls this function to get an error string, e.g. if any
1684     of the handler functions returns \c false.
1685 */
1686 
1687 
1688 /*!
1689     \class QXmlErrorHandler
1690     \obsolete
1691     \reentrant
1692     \brief The QXmlErrorHandler class provides an interface to report
1693     errors in XML data.
1694 
1695     \inmodule QtXml
1696     \ingroup xml-tools
1697 
1698     If you want your application to report errors to the user or to
1699     perform customized error handling, you should subclass this class.
1700 
1701     You can set the error handler with QXmlReader::setErrorHandler().
1702 
1703     Errors can be reported using warning(), error() and fatalError(),
1704     with the error text being reported with errorString().
1705 
1706     \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
1707         QXmlLexicalHandler
1708 */
1709 
1710 /*!
1711     \fn QXmlErrorHandler::~QXmlErrorHandler()
1712 
1713     Destroys the error handler.
1714 */
1715 
1716 /*!
1717     \fn bool QXmlErrorHandler::warning(const QXmlParseException& exception)
1718 
1719     A reader might use this function to report a warning. Warnings are
1720     conditions that are not errors or fatal errors as defined by the
1721     XML 1.0 specification. Details of the warning are stored in \a
1722     exception.
1723 
1724     If this function returns \c false the reader stops parsing and
1725     reports an error. The reader uses the function errorString() to
1726     get the error message.
1727 */
1728 
1729 /*!
1730     \fn bool QXmlErrorHandler::error(const QXmlParseException& exception)
1731 
1732     A reader might use this function to report a recoverable error. A
1733     recoverable error corresponds to the definiton of "error" in
1734     section 1.2 of the XML 1.0 specification. Details of the error are
1735     stored in \a exception.
1736 
1737     The reader must continue to provide normal parsing events after
1738     invoking this function.
1739 
1740     If this function returns \c false the reader stops parsing and
1741     reports an error. The reader uses the function errorString() to
1742     get the error message.
1743 */
1744 
1745 /*!
1746 \fn bool QXmlErrorHandler::fatalError(const QXmlParseException& exception)
1747 
1748 A reader must use this function to report a non-recoverable error.
1749 Details of the error are stored in \a exception.
1750 
1751 If this function returns \c true the reader might try to go on
1752 parsing and reporting further errors, but no regular parsing
1753 events are reported.
1754 */
1755 
1756 /*!
1757     \fn QString QXmlErrorHandler::errorString() const
1758 
1759     The reader calls this function to get an error string if any of
1760     the handler functions returns \c false.
1761 */
1762 
1763 
1764 /*!
1765     \class QXmlDTDHandler
1766     \obsolete
1767     \reentrant
1768     \brief The QXmlDTDHandler class provides an interface to report
1769     DTD content of XML data.
1770 
1771     \inmodule QtXml
1772     \ingroup xml-tools
1773 
1774     If an application needs information about notations and unparsed
1775     entities, it can implement this interface and register an instance
1776     with QXmlReader::setDTDHandler().
1777 
1778     Note that this interface includes only those DTD events that the
1779     XML recommendation requires processors to report, i.e. notation
1780     and unparsed entity declarations using notationDecl() and
1781     unparsedEntityDecl() respectively.
1782 
1783     \sa QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler,
1784         QXmlLexicalHandler
1785 */
1786 
1787 /*!
1788     \fn QXmlDTDHandler::~QXmlDTDHandler()
1789 
1790     Destroys the DTD handler.
1791 */
1792 
1793 /*!
1794     \fn bool QXmlDTDHandler::notationDecl(const QString& name, const QString& publicId, const QString& systemId)
1795 
1796     The reader calls this function when it has parsed a notation
1797     declaration.
1798 
1799     The argument \a name is the notation name, \a publicId is the
1800     notation's public identifier and \a systemId is the notation's
1801     system identifier.
1802 
1803     If this function returns \c false the reader stops parsing and
1804     reports an error. The reader uses the function errorString() to
1805     get the error message.
1806 */
1807 
1808 /*!
1809     \fn bool QXmlDTDHandler::unparsedEntityDecl(const QString& name, const QString& publicId, const QString& systemId, const QString& notationName)
1810 
1811     The reader calls this function when it finds an unparsed entity
1812     declaration.
1813 
1814     The argument \a name is the unparsed entity's name, \a publicId is
1815     the entity's public identifier, \a systemId is the entity's system
1816     identifier and \a notationName is the name of the associated
1817     notation.
1818 
1819     If this function returns \c false the reader stops parsing and
1820     reports an error. The reader uses the function errorString() to
1821     get the error message.
1822 */
1823 
1824 /*!
1825     \fn QString QXmlDTDHandler::errorString() const
1826 
1827     The reader calls this function to get an error string if any of
1828     the handler functions returns \c false.
1829 */
1830 
1831 
1832 /*!
1833     \class QXmlEntityResolver
1834     \obsolete
1835     \reentrant
1836     \brief The QXmlEntityResolver class provides an interface to
1837     resolve external entities contained in XML data.
1838 
1839     \inmodule QtXml
1840     \ingroup xml-tools
1841 
1842     If an application needs to implement customized handling for
1843     external entities, it must implement this interface, i.e.
1844     resolveEntity(), and register it with
1845     QXmlReader::setEntityResolver().
1846 
1847     \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlErrorHandler,
1848         QXmlLexicalHandler
1849 */
1850 
1851 /*!
1852     \fn QXmlEntityResolver::~QXmlEntityResolver()
1853 
1854     Destroys the entity resolver.
1855 */
1856 
1857 /*!
1858     \fn bool QXmlEntityResolver::resolveEntity(const QString& publicId, const QString& systemId, QXmlInputSource*& ret)
1859 
1860     The reader calls this function before it opens any external
1861     entity, except the top-level document entity. The application may
1862     request the reader to resolve the entity itself (\a ret is 0) or
1863     to use an entirely different input source (\a ret points to the
1864     input source).
1865 
1866     The reader deletes the input source \a ret when it no longer needs
1867     it, so you should allocate it on the heap with \c new.
1868 
1869     The argument \a publicId is the public identifier of the external
1870     entity, \a systemId is the system identifier of the external
1871     entity and \a ret is the return value of this function. If \a ret
1872     is 0 the reader should resolve the entity itself, if it is
1873     non-zero it must point to an input source which the reader uses
1874     instead.
1875 
1876     If this function returns \c false the reader stops parsing and
1877     reports an error. The reader uses the function errorString() to
1878     get the error message.
1879 */
1880 
1881 /*!
1882     \fn QString QXmlEntityResolver::errorString() const
1883 
1884     The reader calls this function to get an error string if any of
1885     the handler functions returns \c false.
1886 */
1887 
1888 
1889 /*!
1890     \class QXmlLexicalHandler
1891     \obsolete
1892     \reentrant
1893     \brief The QXmlLexicalHandler class provides an interface to
1894     report the lexical content of XML data.
1895 
1896     \inmodule QtXml
1897     \ingroup xml-tools
1898 
1899     The events in the lexical handler apply to the entire document,
1900     not just to the document element, and all lexical handler events
1901     appear between the content handler's startDocument and endDocument
1902     events.
1903 
1904     You can set the lexical handler with
1905     QXmlReader::setLexicalHandler().
1906 
1907     This interface's design is based on the SAX2 extension
1908     LexicalHandler.
1909 
1910     The interface provides the startDTD(), endDTD(), startEntity(),
1911     endEntity(), startCDATA(), endCDATA() and comment() functions.
1912 
1913     \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
1914         QXmlErrorHandler
1915 */
1916 
1917 /*!
1918     \fn QXmlLexicalHandler::~QXmlLexicalHandler()
1919 
1920     Destroys the lexical handler.
1921 */
1922 
1923 /*!
1924     \fn bool QXmlLexicalHandler::startDTD(const QString& name, const QString& publicId, const QString& systemId)
1925 
1926     The reader calls this function to report the start of a DTD
1927     declaration, if any. It reports the name of the document type in
1928     \a name, the public identifier in \a publicId and the system
1929     identifier in \a systemId.
1930 
1931     If the public identifier is missing, \a publicId is set to
1932     an empty string. If the system identifier is missing, \a systemId is
1933     set to an empty string. Note that it is not valid XML to have a
1934     public identifier but no system identifier; in such cases a parse
1935     error will occur.
1936 
1937     All declarations reported through QXmlDTDHandler or
1938     QXmlDeclHandler appear between the startDTD() and endDTD() calls.
1939 
1940     If this function returns \c false the reader stops parsing and
1941     reports an error. The reader uses the function errorString() to
1942     get the error message.
1943 
1944     \sa endDTD()
1945 */
1946 
1947 /*!
1948     \fn bool QXmlLexicalHandler::endDTD()
1949 
1950     The reader calls this function to report the end of a DTD
1951     declaration, if any.
1952 
1953     If this function returns \c false the reader stops parsing and
1954     reports an error. The reader uses the function errorString() to
1955     get the error message.
1956 
1957     \sa startDTD()
1958 */
1959 
1960 /*!
1961     \fn bool QXmlLexicalHandler::startEntity(const QString& name)
1962 
1963     The reader calls this function to report the start of an entity
1964     called \a name.
1965 
1966     Note that if the entity is unknown, the reader reports it through
1967     QXmlContentHandler::skippedEntity() and not through this
1968     function.
1969 
1970     If this function returns \c false the reader stops parsing and
1971     reports an error. The reader uses the function errorString() to
1972     get the error message.
1973 
1974     \sa endEntity(), QXmlSimpleReader::setFeature()
1975 */
1976 
1977 /*!
1978     \fn bool QXmlLexicalHandler::endEntity(const QString& name)
1979 
1980     The reader calls this function to report the end of an entity
1981     called \a name.
1982 
1983     For every startEntity() call, there is a corresponding endEntity()
1984     call. The calls to startEntity() and endEntity() are properly
1985     nested.
1986 
1987     If this function returns \c false the reader stops parsing and
1988     reports an error. The reader uses the function errorString() to
1989     get the error message.
1990 
1991     \sa startEntity(), QXmlContentHandler::skippedEntity(), QXmlSimpleReader::setFeature()
1992 */
1993 
1994 /*!
1995     \fn bool QXmlLexicalHandler::startCDATA()
1996 
1997     The reader calls this function to report the start of a CDATA
1998     section. The content of the CDATA section is reported through the
1999     QXmlContentHandler::characters() function. This function is
2000     intended only to report the boundary.
2001 
2002     If this function returns \c false the reader stops parsing and
2003     reports an error. The reader uses the function errorString() to
2004     get the error message.
2005 
2006     \sa endCDATA()
2007 */
2008 
2009 /*!
2010     \fn bool QXmlLexicalHandler::endCDATA()
2011 
2012     The reader calls this function to report the end of a CDATA
2013     section.
2014 
2015     If this function returns \c false the reader stops parsing and reports
2016     an error. The reader uses the function errorString() to get the error
2017     message.
2018 
2019     \sa startCDATA(), QXmlContentHandler::characters()
2020 */
2021 
2022 /*!
2023     \fn bool QXmlLexicalHandler::comment(const QString& ch)
2024 
2025     The reader calls this function to report an XML comment anywhere
2026     in the document. It reports the text of the comment in \a ch.
2027 
2028     If this function returns \c false the reader stops parsing and
2029     reports an error. The reader uses the function errorString() to
2030     get the error message.
2031 */
2032 
2033 /*!
2034     \fn QString QXmlLexicalHandler::errorString() const
2035 
2036     The reader calls this function to get an error string if any of
2037     the handler functions returns \c false.
2038 */
2039 
2040 
2041 /*!
2042     \class QXmlDeclHandler
2043     \obsolete
2044     \reentrant
2045     \brief The QXmlDeclHandler class provides an interface to report declaration
2046     content of XML data.
2047 
2048     \inmodule QtXml
2049     \ingroup xml-tools
2050 
2051     You can set the declaration handler with
2052     QXmlReader::setDeclHandler().
2053 
2054     This interface is based on the SAX2 extension DeclHandler.
2055 
2056     The interface provides attributeDecl(), internalEntityDecl() and
2057     externalEntityDecl() functions.
2058 
2059     \sa QXmlDTDHandler, QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler,
2060         QXmlLexicalHandler
2061 */
2062 
2063 /*!
2064     \fn QXmlDeclHandler::~QXmlDeclHandler()
2065 
2066     Destroys the declaration handler.
2067 */
2068 
2069 /*!
2070     \fn bool QXmlDeclHandler::attributeDecl(const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value)
2071 
2072     The reader calls this function to report an attribute type
2073     declaration. Only the effective (first) declaration for an
2074     attribute is reported.
2075 
2076     The reader passes the name of the associated element in \a eName
2077     and the name of the attribute in \a aName. It passes a string that
2078     represents the attribute type in \a type and a string that
2079     represents the attribute default in \a valueDefault. This string
2080     is one of "#IMPLIED", "#REQUIRED", "#FIXED" or an empty string (if
2081     none of the others applies). The reader passes the attribute's
2082     default value in \a value. If no default value is specified in the
2083     XML file, \a value is an empty string.
2084 
2085     If this function returns \c false the reader stops parsing and
2086     reports an error. The reader uses the function errorString() to
2087     get the error message.
2088 */
2089 
2090 /*!
2091     \fn bool QXmlDeclHandler::internalEntityDecl(const QString& name, const QString& value)
2092 
2093     The reader calls this function to report an internal entity
2094     declaration. Only the effective (first) declaration is reported.
2095 
2096     The reader passes the name of the entity in \a name and the value
2097     of the entity in \a value.
2098 
2099     If this function returns \c false the reader stops parsing and
2100     reports an error. The reader uses the function errorString() to
2101     get the error message.
2102 */
2103 
2104 /*!
2105     \fn bool QXmlDeclHandler::externalEntityDecl(const QString& name, const QString& publicId, const QString& systemId)
2106 
2107     The reader calls this function to report a parsed external entity
2108     declaration. Only the effective (first) declaration for each
2109     entity is reported.
2110 
2111     The reader passes the name of the entity in \a name, the public
2112     identifier in \a publicId and the system identifier in \a
2113     systemId. If there is no public identifier specified, it passes
2114     an empty string in \a publicId.
2115 
2116     If this function returns \c false the reader stops parsing and
2117     reports an error. The reader uses the function errorString() to
2118     get the error message.
2119 */
2120 
2121 /*!
2122     \fn QString QXmlDeclHandler::errorString() const
2123 
2124     The reader calls this function to get an error string if any of
2125     the handler functions returns \c false.
2126 */
2127 
2128 
2129 /*!
2130     \class QXmlDefaultHandler
2131     \obsolete
2132     \reentrant
2133     \brief The QXmlDefaultHandler class provides a default implementation of all
2134     the XML handler classes.
2135 
2136     \inmodule QtXml
2137     \ingroup xml-tools
2138 
2139     This class gathers together the features of
2140     the specialized handler classes, making it a convenient
2141     starting point when implementing custom handlers for
2142     subclasses of QXmlReader, particularly QXmlSimpleReader.
2143     The virtual functions from each of the base classes are
2144     reimplemented in this class, providing sensible default behavior
2145     for many common cases. By subclassing this class, and
2146     overriding these functions, you can concentrate
2147     on implementing the parts of the handler relevant to your
2148     application.
2149 
2150     The XML reader must be told which handler to use for different
2151     kinds of events during parsing. This means that, although
2152     QXmlDefaultHandler provides default implementations of functions
2153     inherited from all its base classes, we can still use specialized
2154     handlers for particular kinds of events.
2155 
2156     For example, QXmlDefaultHandler subclasses both
2157     QXmlContentHandler and QXmlErrorHandler, so by subclassing
2158     it we can use the same handler for both of the following
2159     reader functions:
2160 
2161     \snippet rsslisting/listing.cpp 0
2162 
2163     Since the reader will inform the handler of parsing errors, it is
2164     necessary to reimplement QXmlErrorHandler::fatalError() if, for
2165     example, we want to stop parsing when such an error occurs:
2166 
2167     \snippet rsslisting/handler.cpp 0
2168 
2169     The above function returns \c false, which tells the reader to stop
2170     parsing. To continue to use the same reader,
2171     it is necessary to create a new handler instance, and set up the
2172     reader to use it in the manner described above.
2173 
2174     It is useful to examine some of the functions inherited by
2175     QXmlDefaultHandler, and consider why they might be
2176     reimplemented in a custom handler.
2177     Custom handlers will typically reimplement
2178     QXmlContentHandler::startDocument() to prepare the handler for
2179     new content. Document elements and the text within them can be
2180     processed by reimplementing QXmlContentHandler::startElement(),
2181     QXmlContentHandler::endElement(), and
2182     QXmlContentHandler::characters().
2183     You may want to reimplement QXmlContentHandler::endDocument()
2184     to perform some finalization or validation on the content once the
2185     document has been read completely.
2186 
2187     \sa QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver,
2188         QXmlErrorHandler, QXmlLexicalHandler
2189 */
2190 
2191 /*!
2192     \fn QXmlDefaultHandler::QXmlDefaultHandler()
2193 
2194     Constructs a handler for use with subclasses of QXmlReader.
2195 */
QXmlDefaultHandler()2196 QXmlDefaultHandler::QXmlDefaultHandler()
2197 {
2198     // ### In Qt 5.0, this function was inlined and d was not initialized
2199     // The member cannot be used until Qt 6.0
2200     Q_UNUSED(d);
2201 }
2202 
2203 /*!
2204     \fn QXmlDefaultHandler::~QXmlDefaultHandler()
2205 
2206     Destroys the handler.
2207 */
~QXmlDefaultHandler()2208 QXmlDefaultHandler::~QXmlDefaultHandler()
2209 {
2210 }
2211 
2212 /*!
2213     \reimp
2214 
2215     This reimplementation does nothing.
2216 */
setDocumentLocator(QXmlLocator *)2217 void QXmlDefaultHandler::setDocumentLocator(QXmlLocator*)
2218 {
2219 }
2220 
2221 /*!
2222     \reimp
2223 
2224     This reimplementation does nothing.
2225 */
startDocument()2226 bool QXmlDefaultHandler::startDocument()
2227 {
2228     return true;
2229 }
2230 
2231 /*!
2232     \reimp
2233 
2234     This reimplementation does nothing.
2235 */
endDocument()2236 bool QXmlDefaultHandler::endDocument()
2237 {
2238     return true;
2239 }
2240 
2241 /*!
2242     \reimp
2243 
2244     This reimplementation does nothing.
2245 */
startPrefixMapping(const QString &,const QString &)2246 bool QXmlDefaultHandler::startPrefixMapping(const QString&, const QString&)
2247 {
2248     return true;
2249 }
2250 
2251 /*!
2252     \reimp
2253 
2254     This reimplementation does nothing.
2255 */
endPrefixMapping(const QString &)2256 bool QXmlDefaultHandler::endPrefixMapping(const QString&)
2257 {
2258     return true;
2259 }
2260 
2261 /*!
2262     \reimp
2263 
2264     This reimplementation does nothing.
2265 */
startElement(const QString &,const QString &,const QString &,const QXmlAttributes &)2266 bool QXmlDefaultHandler::startElement(const QString&, const QString&,
2267         const QString&, const QXmlAttributes&)
2268 {
2269     return true;
2270 }
2271 
2272 /*!
2273     \reimp
2274 
2275     This reimplementation does nothing.
2276 */
endElement(const QString &,const QString &,const QString &)2277 bool QXmlDefaultHandler::endElement(const QString&, const QString&,
2278         const QString&)
2279 {
2280     return true;
2281 }
2282 
2283 /*!
2284     \reimp
2285 
2286     This reimplementation does nothing.
2287 */
characters(const QString &)2288 bool QXmlDefaultHandler::characters(const QString&)
2289 {
2290     return true;
2291 }
2292 
2293 /*!
2294     \reimp
2295 
2296     This reimplementation does nothing.
2297 */
ignorableWhitespace(const QString &)2298 bool QXmlDefaultHandler::ignorableWhitespace(const QString&)
2299 {
2300     return true;
2301 }
2302 
2303 /*!
2304     \reimp
2305 
2306     This reimplementation does nothing.
2307 */
processingInstruction(const QString &,const QString &)2308 bool QXmlDefaultHandler::processingInstruction(const QString&,
2309         const QString&)
2310 {
2311     return true;
2312 }
2313 
2314 /*!
2315     \reimp
2316 
2317     This reimplementation does nothing.
2318 */
skippedEntity(const QString &)2319 bool QXmlDefaultHandler::skippedEntity(const QString&)
2320 {
2321     return true;
2322 }
2323 
2324 /*!
2325     \reimp
2326 
2327     This reimplementation does nothing.
2328 */
warning(const QXmlParseException &)2329 bool QXmlDefaultHandler::warning(const QXmlParseException&)
2330 {
2331     return true;
2332 }
2333 
2334 /*!
2335     \reimp
2336 
2337     This reimplementation does nothing.
2338 */
error(const QXmlParseException &)2339 bool QXmlDefaultHandler::error(const QXmlParseException&)
2340 {
2341     return true;
2342 }
2343 
2344 /*!
2345     \reimp
2346 
2347     This reimplementation does nothing.
2348 */
fatalError(const QXmlParseException &)2349 bool QXmlDefaultHandler::fatalError(const QXmlParseException&)
2350 {
2351     return true;
2352 }
2353 
2354 /*!
2355     \reimp
2356 
2357     This reimplementation does nothing.
2358 */
notationDecl(const QString &,const QString &,const QString &)2359 bool QXmlDefaultHandler::notationDecl(const QString&, const QString&,
2360         const QString&)
2361 {
2362     return true;
2363 }
2364 
2365 /*!
2366     \reimp
2367 
2368     This reimplementation does nothing.
2369 */
unparsedEntityDecl(const QString &,const QString &,const QString &,const QString &)2370 bool QXmlDefaultHandler::unparsedEntityDecl(const QString&, const QString&,
2371         const QString&, const QString&)
2372 {
2373     return true;
2374 }
2375 
2376 /*!
2377     \reimp
2378 
2379     Sets \a ret to \nullptr, so that the reader uses the system identifier
2380     provided in the XML document.
2381 */
resolveEntity(const QString &,const QString &,QXmlInputSource * & ret)2382 bool QXmlDefaultHandler::resolveEntity(const QString&, const QString&,
2383         QXmlInputSource*& ret)
2384 {
2385     ret = nullptr;
2386     return true;
2387 }
2388 
2389 /*!
2390     \reimp
2391 
2392     Returns the default error string.
2393 */
errorString() const2394 QString QXmlDefaultHandler::errorString() const
2395 {
2396     return QString::fromLatin1(XMLERR_ERRORBYCONSUMER);
2397 }
2398 
2399 /*!
2400     \reimp
2401 
2402     This reimplementation does nothing.
2403 */
startDTD(const QString &,const QString &,const QString &)2404 bool QXmlDefaultHandler::startDTD(const QString&, const QString&, const QString&)
2405 {
2406     return true;
2407 }
2408 
2409 /*!
2410     \reimp
2411 
2412     This reimplementation does nothing.
2413 */
endDTD()2414 bool QXmlDefaultHandler::endDTD()
2415 {
2416     return true;
2417 }
2418 
2419 /*!
2420     \reimp
2421 
2422     This reimplementation does nothing.
2423 */
startEntity(const QString &)2424 bool QXmlDefaultHandler::startEntity(const QString&)
2425 {
2426     return true;
2427 }
2428 
2429 /*!
2430     \reimp
2431 
2432     This reimplementation does nothing.
2433 */
endEntity(const QString &)2434 bool QXmlDefaultHandler::endEntity(const QString&)
2435 {
2436     return true;
2437 }
2438 
2439 /*!
2440     \reimp
2441 
2442     This reimplementation does nothing.
2443 */
startCDATA()2444 bool QXmlDefaultHandler::startCDATA()
2445 {
2446     return true;
2447 }
2448 
2449 /*!
2450     \reimp
2451 
2452     This reimplementation does nothing.
2453 */
endCDATA()2454 bool QXmlDefaultHandler::endCDATA()
2455 {
2456     return true;
2457 }
2458 
2459 /*!
2460     \reimp
2461 
2462     This reimplementation does nothing.
2463 */
comment(const QString &)2464 bool QXmlDefaultHandler::comment(const QString&)
2465 {
2466     return true;
2467 }
2468 
2469 /*!
2470     \reimp
2471 
2472     This reimplementation does nothing.
2473 */
attributeDecl(const QString &,const QString &,const QString &,const QString &,const QString &)2474 bool QXmlDefaultHandler::attributeDecl(const QString&, const QString&, const QString&, const QString&, const QString&)
2475 {
2476     return true;
2477 }
2478 
2479 /*!
2480     \reimp
2481 
2482     This reimplementation does nothing.
2483 */
internalEntityDecl(const QString &,const QString &)2484 bool QXmlDefaultHandler::internalEntityDecl(const QString&, const QString&)
2485 {
2486     return true;
2487 }
2488 
2489 /*!
2490     \reimp
2491 
2492     This reimplementation does nothing.
2493 */
externalEntityDecl(const QString &,const QString &,const QString &)2494 bool QXmlDefaultHandler::externalEntityDecl(const QString&, const QString&, const QString&)
2495 {
2496     return true;
2497 }
2498 
2499 
2500 /*********************************************
2501  *
2502  * QXmlSimpleReaderPrivate
2503  *
2504  *********************************************/
2505 
atEnd()2506 inline bool QXmlSimpleReaderPrivate::atEnd()
2507 {
2508     return (c.unicode()|0x0001) == 0xffff;
2509 }
2510 
stringClear()2511 inline void QXmlSimpleReaderPrivate::stringClear()
2512 {
2513     stringValueLen = 0; stringArrayPos = 0;
2514 }
nameClear()2515 inline void QXmlSimpleReaderPrivate::nameClear()
2516 {
2517     nameValueLen = 0; nameArrayPos = 0;
2518 }
2519 
refClear()2520 inline void QXmlSimpleReaderPrivate::refClear()
2521 {
2522     refValueLen = 0; refArrayPos = 0;
2523 }
2524 
QXmlSimpleReaderPrivate(QXmlSimpleReader * reader)2525 QXmlSimpleReaderPrivate::QXmlSimpleReaderPrivate(QXmlSimpleReader *reader)
2526 {
2527     q_ptr = reader;
2528     parseStack = nullptr;
2529 
2530     locator.reset(new QXmlSimpleReaderLocator(reader));
2531     entityRes  = nullptr;
2532     dtdHnd     = nullptr;
2533     contentHnd = nullptr;
2534     errorHnd   = nullptr;
2535     lexicalHnd = nullptr;
2536     declHnd    = nullptr;
2537 
2538     // default feature settings
2539     useNamespaces = true;
2540     useNamespacePrefixes = false;
2541     reportWhitespaceCharData = true;
2542     reportEntities = false;
2543 }
2544 
~QXmlSimpleReaderPrivate()2545 QXmlSimpleReaderPrivate::~QXmlSimpleReaderPrivate()
2546 {
2547     delete parseStack;
2548 }
2549 
initIncrementalParsing()2550 void QXmlSimpleReaderPrivate::initIncrementalParsing()
2551 {
2552     if(parseStack)
2553         parseStack->clear();
2554     else
2555         parseStack = new QStack<ParseState>;
2556 }
2557 
2558 /*********************************************
2559  *
2560  * QXmlSimpleReader
2561  *
2562  *********************************************/
2563 
2564 /*!
2565     \class QXmlReader
2566     \obsolete
2567     \reentrant
2568     \brief The QXmlReader class provides an interface for XML readers (i.e.
2569     parsers).
2570 
2571     \inmodule QtXml
2572     \ingroup xml-tools
2573 
2574     This abstract class provides an interface for all of Qt's XML
2575     readers. Currently there is only one implementation of a reader
2576     included in Qt's XML module: QXmlSimpleReader. In future releases
2577     there might be more readers with different properties available
2578     (e.g. a validating parser).
2579 
2580     The design of the XML classes follows the \l{SAX2 Java interface}, with
2581     the names adapted to fit Qt naming conventions. It should be very
2582     easy for anybody who has worked with SAX2 to get started with the
2583     Qt XML classes.
2584 
2585     All readers use the class QXmlInputSource to read the input
2586     document. Since you are normally interested in particular content
2587     in the XML document, the reader reports the content through
2588     special handler classes (QXmlDTDHandler, QXmlDeclHandler,
2589     QXmlContentHandler, QXmlEntityResolver, QXmlErrorHandler and
2590     QXmlLexicalHandler), which you must subclass, if you want to
2591     process the contents.
2592 
2593     Since the handler classes only describe interfaces you must
2594     implement all the functions. We provide the QXmlDefaultHandler
2595     class to make this easier: it implements a default behavior (do
2596     nothing) for all functions, so you can subclass it and just
2597     implement the functions you are interested in.
2598 
2599     Features and properties of the reader can be set with setFeature()
2600     and setProperty() respectively. You can set the reader to use your
2601     own subclasses with setEntityResolver(), setDTDHandler(),
2602     setContentHandler(), setErrorHandler(), setLexicalHandler() and
2603     setDeclHandler(). The parse itself is started with a call to
2604     parse().
2605 
2606     Note that this class is now deprecated, please use QXmlStreamReader or
2607     QDomDocument for reading XML files.
2608 
2609     \sa QXmlSimpleReader
2610 */
2611 
2612 /*!
2613     \fn QXmlReader::~QXmlReader()
2614 
2615     Destroys the reader.
2616 */
2617 
2618 /*!
2619     \fn bool QXmlReader::feature(const QString& name, bool *ok) const
2620 
2621     If the reader has the feature called \a name, the feature's value
2622     is returned. If no such feature exists the return value is
2623     undefined.
2624 
2625     If \a ok is not \nullptr: \c{*}\a{ok}  is set to true if the
2626     reader has the feature called \a name; otherwise \c{*}\a{ok} is
2627     set to false.
2628 
2629     \sa setFeature(), hasFeature()
2630 */
2631 
2632 /*!
2633     \fn void QXmlReader::setFeature(const QString& name, bool value)
2634 
2635     Sets the feature called \a name to the given \a value. If the
2636     reader doesn't have the feature nothing happens.
2637 
2638     \sa feature(), hasFeature()
2639 */
2640 
2641 /*!
2642     \fn bool QXmlReader::hasFeature(const QString& name) const
2643 
2644     Returns \c true if the reader has the feature called \a name;
2645     otherwise returns \c false.
2646 
2647     \sa feature(), setFeature()
2648 */
2649 
2650 /*!
2651     \fn void* QXmlReader::property(const QString& name, bool *ok) const
2652 
2653     If the reader has the property \a name, this function returns the
2654     value of the property; otherwise the return value is undefined.
2655 
2656     If \a ok is not \nullptr: if the reader has the \a name property
2657     \c{*}\a{ok} is set to true; otherwise \c{*}\a{ok} is set to false.
2658 
2659     \sa setProperty(), hasProperty()
2660 */
2661 
2662 /*!
2663     \fn void QXmlReader::setProperty(const QString& name, void* value)
2664 
2665     Sets the property \a name to \a value. If the reader doesn't have
2666     the property nothing happens.
2667 
2668     \sa property(), hasProperty()
2669 */
2670 
2671 /*!
2672     \fn bool QXmlReader::hasProperty(const QString& name) const
2673 
2674     Returns \c true if the reader has the property \a name; otherwise
2675     returns \c false.
2676 
2677     \sa property(), setProperty()
2678 */
2679 
2680 /*!
2681     \fn void QXmlReader::setEntityResolver(QXmlEntityResolver* handler)
2682 
2683     Sets the entity resolver to \a handler.
2684 
2685     \sa entityResolver()
2686 */
2687 
2688 /*!
2689     \fn QXmlEntityResolver *QXmlReader::entityResolver() const
2690 
2691     Returns the entity resolver or \nullptr if none was set.
2692 
2693     \sa setEntityResolver()
2694 */
2695 
2696 /*!
2697     \fn void QXmlReader::setDTDHandler(QXmlDTDHandler* handler)
2698 
2699     Sets the DTD handler to \a handler.
2700 
2701     \sa DTDHandler()
2702 */
2703 
2704 /*!
2705     \fn QXmlDTDHandler *QXmlReader::DTDHandler() const
2706 
2707     Returns the DTD handler or \nullptr if none was set.
2708 
2709     \sa setDTDHandler()
2710 */
2711 
2712 /*!
2713     \fn void QXmlReader::setContentHandler(QXmlContentHandler* handler)
2714 
2715     Sets the content handler to \a handler.
2716 
2717     \sa contentHandler()
2718 */
2719 
2720 /*!
2721     \fn QXmlContentHandler *QXmlReader::contentHandler() const
2722 
2723     Returns the content handler or \nullptr if none was set.
2724 
2725     \sa setContentHandler()
2726 */
2727 
2728 /*!
2729     \fn void QXmlReader::setErrorHandler(QXmlErrorHandler* handler)
2730 
2731     Sets the error handler to \a handler. Clears the error handler if
2732     \a handler is 0.
2733 
2734     \sa errorHandler()
2735 */
2736 
2737 /*!
2738     \fn QXmlErrorHandler *QXmlReader::errorHandler() const
2739 
2740     Returns the error handler or \nullptr if none is set.
2741 
2742     \sa setErrorHandler()
2743 */
2744 
2745 /*!
2746     \fn void QXmlReader::setLexicalHandler(QXmlLexicalHandler* handler)
2747 
2748     Sets the lexical handler to \a handler.
2749 
2750     \sa lexicalHandler()
2751 */
2752 
2753 /*!
2754     \fn QXmlLexicalHandler *QXmlReader::lexicalHandler() const
2755 
2756     Returns the lexical handler or \nullptr if none was set.
2757 
2758     \sa setLexicalHandler()
2759 */
2760 
2761 /*!
2762     \fn void QXmlReader::setDeclHandler(QXmlDeclHandler* handler)
2763 
2764     Sets the declaration handler to \a handler.
2765 
2766     \sa declHandler()
2767 */
2768 
2769 /*!
2770     \fn QXmlDeclHandler *QXmlReader::declHandler() const
2771 
2772     Returns the declaration handler or \nullptr if none was set.
2773 
2774     \sa setDeclHandler()
2775 */
2776 
2777 /*!
2778   \fn bool QXmlReader::parse(const QXmlInputSource &input)
2779 
2780   \obsolete
2781 
2782   Parses the given \a input.
2783 */
2784 
2785 /*!
2786     \fn bool QXmlReader::parse(const QXmlInputSource *input)
2787 
2788     Reads an XML document from \a input and parses it. Returns \c true if
2789     the parsing was successful; otherwise returns \c false.
2790 */
2791 
2792 
2793 /*!
2794     \class QXmlSimpleReader
2795     \obsolete
2796     \nonreentrant
2797     \brief The QXmlSimpleReader class provides an implementation of a
2798     simple XML parser.
2799 
2800     \inmodule QtXml
2801     \ingroup xml-tools
2802 
2803 
2804     This XML reader is suitable for a wide range of applications. It
2805     is able to parse well-formed XML and can report the namespaces of
2806     elements to a content handler; however, it does not parse any
2807     external entities. For historical reasons, Attribute Value
2808     Normalization and End-of-Line Handling as described in the XML 1.0
2809     specification is not performed.
2810 
2811     The easiest pattern of use for this class is to create a reader
2812     instance, define an input source, specify the handlers to be used
2813     by the reader, and parse the data.
2814 
2815     For example, we could use a QFile to supply the input. Here, we
2816     create a reader, and define an input source to be used by the
2817     reader:
2818 
2819     \snippet simpleparse/main.cpp 0
2820 
2821     A handler lets us perform actions when the reader encounters
2822     certain types of content, or if errors in the input are found. The
2823     reader must be told which handler to use for each type of
2824     event. For many common applications, we can create a custom
2825     handler by subclassing QXmlDefaultHandler, and use this to handle
2826     both error and content events:
2827 
2828     \snippet simpleparse/main.cpp 1
2829 
2830     If you don't set at least the content and error handlers, the
2831     parser will fall back on its default behavior---and will do
2832     nothing.
2833 
2834     The most convenient way to handle the input is to read it in a
2835     single pass using the parse() function with an argument that
2836     specifies the input source:
2837 
2838     \snippet simpleparse/main.cpp 2
2839 
2840     If you can't parse the entire input in one go (for example, it is
2841     huge, or is being delivered over a network connection), data can
2842     be fed to the parser in pieces. This is achieved by telling
2843     parse() to work incrementally, and making subsequent calls to the
2844     parseContinue() function, until all the data has been processed.
2845 
2846     A common way to perform incremental parsing is to connect the \c
2847     readyRead() signal of a \l{QNetworkReply} {network reply} a slot,
2848     and handle the incoming data there. See QNetworkAccessManager.
2849 
2850     Aspects of the parsing behavior can be adapted using setFeature()
2851     and setProperty().
2852 
2853     \snippet code/src_xml_sax_qxml.cpp 0
2854 
2855     QXmlSimpleReader is not reentrant. If you want to use the class
2856     in threaded code, lock the code using QXmlSimpleReader with a
2857     locking mechanism, such as a QMutex.
2858 
2859     Note that this class is now deprecated, please use QXmlStreamReader or
2860     QDomDocument for reading XML files.
2861 */
2862 
is_S(QChar ch)2863 static inline bool is_S(QChar ch)
2864 {
2865     ushort uc = ch.unicode();
2866     return (uc == ' ' || uc == '\t' || uc == '\n' || uc == '\r');
2867 }
2868 
2869 enum NameChar { NameBeginning, NameNotBeginning, NotName };
2870 
2871 static const char Begi = (char)NameBeginning;
2872 static const char NtBg = (char)NameNotBeginning;
2873 static const char NotN = (char)NotName;
2874 
2875 static const char nameCharTable[128] =
2876 {
2877 // 0x00
2878     NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
2879     NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
2880 // 0x10
2881     NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
2882     NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
2883 // 0x20 (0x2D is '-', 0x2E is '.')
2884     NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
2885     NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
2886 // 0x30 (0x30..0x39 are '0'..'9', 0x3A is ':')
2887     NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
2888     NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
2889 // 0x40 (0x41..0x5A are 'A'..'Z')
2890     NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2891     Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2892 // 0x50 (0x5F is '_')
2893     Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2894     Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
2895 // 0x60 (0x61..0x7A are 'a'..'z')
2896     NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2897     Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2898 // 0x70
2899     Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
2900     Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
2901 };
2902 
fastDetermineNameChar(QChar ch)2903 static inline NameChar fastDetermineNameChar(QChar ch)
2904 {
2905     ushort uc = ch.unicode();
2906     if (!(uc & ~0x7f)) // uc < 128
2907         return (NameChar)nameCharTable[uc];
2908 
2909     QChar::Category cat = ch.category();
2910     // ### some these categories might be slightly wrong
2911     if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
2912         || cat == QChar::Number_Letter)
2913         return NameBeginning;
2914     if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
2915                 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
2916         return NameNotBeginning;
2917     return NotName;
2918 }
2919 
determineNameChar(QChar ch)2920 static NameChar determineNameChar(QChar ch)
2921 {
2922     return fastDetermineNameChar(ch);
2923 }
2924 
2925 /*!
2926     Constructs a simple XML reader.
2927 
2928 */
QXmlSimpleReader()2929 QXmlSimpleReader::QXmlSimpleReader()
2930     : d_ptr(new QXmlSimpleReaderPrivate(this))
2931 {
2932 }
2933 
2934 /*!
2935     Destroys the simple XML reader.
2936 */
~QXmlSimpleReader()2937 QXmlSimpleReader::~QXmlSimpleReader()
2938 {
2939 }
2940 
2941 /*!
2942     \reimp
2943 */
feature(const QString & name,bool * ok) const2944 bool QXmlSimpleReader::feature(const QString& name, bool *ok) const
2945 {
2946     const QXmlSimpleReaderPrivate *d = d_func();
2947 
2948     if (ok)
2949         *ok = true;
2950     if (name == QLatin1String("http://xml.org/sax/features/namespaces")) {
2951         return d->useNamespaces;
2952     } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) {
2953         return d->useNamespacePrefixes;
2954     } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
2955                || name == QLatin1String("http://qt-project.org/xml/features/report-whitespace-only-CharData")) {
2956         return d->reportWhitespaceCharData;
2957     } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
2958                || name == QLatin1String("http://qt-project.org/xml/features/report-start-end-entity")) {
2959         return d->reportEntities;
2960     } else {
2961         qWarning("Unknown feature %s", name.toLatin1().data());
2962         if (ok)
2963             *ok = false;
2964     }
2965     return false;
2966 }
2967 
2968 /*!
2969     Turns on the feature \a name if \a enable is true; otherwise turns it off.
2970 
2971     The \a name parameter must be one of the following strings:
2972     \table
2973     \header \li Feature \li Default \li Notes
2974     \row \li \e http://xml.org/sax/features/namespaces
2975          \li true
2976          \li If enabled, namespaces are reported to the content handler.
2977     \row \li \e http://xml.org/sax/features/namespace-prefixes
2978          \li false
2979          \li If enabled, the original prefixed names
2980             and attributes used for namespace declarations are
2981             reported.
2982     \row \li \e http://qt-project.org/xml/features/report-whitespace-only-CharData
2983          \li true
2984          \li If enabled, CharData that consist of
2985             only whitespace characters are reported
2986             using QXmlContentHandler::characters(). If disabled, whitespace is silently
2987             discarded.
2988     \row \li \e http://qt-project.org/xml/features/report-start-end-entity
2989          \li false
2990          \li If enabled, the parser reports
2991             QXmlContentHandler::startEntity() and
2992             QXmlContentHandler::endEntity() events, so character data
2993             might be reported in chunks.
2994             If disabled, the parser does not report these events, but
2995             silently substitutes the entities, and reports the character
2996             data in one chunk.
2997     \endtable
2998 
2999     \sa feature(), hasFeature()
3000 */
setFeature(const QString & name,bool enable)3001 void QXmlSimpleReader::setFeature(const QString& name, bool enable)
3002 {
3003     Q_D(QXmlSimpleReader);
3004     if (name == QLatin1String("http://xml.org/sax/features/namespaces")) {
3005         d->useNamespaces = enable;
3006     } else if (name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")) {
3007         d->useNamespacePrefixes = enable;
3008     } else if (name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
3009                || name == QLatin1String("http://qt-project.org/xml/features/report-whitespace-only-CharData")) {
3010         d->reportWhitespaceCharData = enable;
3011     } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
3012                || name == QLatin1String("http://qt-project.org/xml/features/report-start-end-entity")) {
3013         d->reportEntities = enable;
3014     } else {
3015         qWarning("Unknown feature %s", name.toLatin1().data());
3016     }
3017 }
3018 
3019 /*! \reimp
3020 */
hasFeature(const QString & name) const3021 bool QXmlSimpleReader::hasFeature(const QString& name) const
3022 {
3023     if (name == QLatin1String("http://xml.org/sax/features/namespaces")
3024         || name == QLatin1String("http://xml.org/sax/features/namespace-prefixes")
3025         || name == QLatin1String("http://trolltech.com/xml/features/report-whitespace-only-CharData") // For compat with Qt 4
3026         || name == QLatin1String("http://qt-project.org/xml/features/report-whitespace-only-CharData")
3027         || name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4
3028         || name == QLatin1String("http://qt-project.org/xml/features/report-start-end-entity")) {
3029         return true;
3030     } else {
3031         return false;
3032     }
3033 }
3034 
3035 /*! \reimp
3036 */
property(const QString &,bool * ok) const3037 void* QXmlSimpleReader::property(const QString&, bool *ok) const
3038 {
3039     if (ok)
3040         *ok = false;
3041     return nullptr;
3042 }
3043 
3044 /*! \reimp
3045 */
setProperty(const QString &,void *)3046 void QXmlSimpleReader::setProperty(const QString&, void*)
3047 {
3048 }
3049 
3050 /*!
3051     \reimp
3052 */
hasProperty(const QString &) const3053 bool QXmlSimpleReader::hasProperty(const QString&) const
3054 {
3055     return false;
3056 }
3057 
3058 /*!
3059     \reimp
3060 */
setEntityResolver(QXmlEntityResolver * handler)3061 void QXmlSimpleReader::setEntityResolver(QXmlEntityResolver* handler)
3062 {
3063     Q_D(QXmlSimpleReader);
3064     d->entityRes = handler;
3065 }
3066 
3067 /*!
3068     \reimp
3069 */
entityResolver() const3070 QXmlEntityResolver* QXmlSimpleReader::entityResolver() const
3071 {
3072     const QXmlSimpleReaderPrivate *d = d_func();
3073     return d->entityRes;
3074 }
3075 
3076 /*!
3077     \reimp
3078 */
setDTDHandler(QXmlDTDHandler * handler)3079 void QXmlSimpleReader::setDTDHandler(QXmlDTDHandler* handler)
3080 {
3081     Q_D(QXmlSimpleReader);
3082     d->dtdHnd = handler;
3083 }
3084 
3085 /*!
3086     \reimp
3087 */
DTDHandler() const3088 QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const
3089 {
3090     const QXmlSimpleReaderPrivate *d = d_func();
3091     return d->dtdHnd;
3092 }
3093 
3094 /*!
3095     \reimp
3096 */
setContentHandler(QXmlContentHandler * handler)3097 void QXmlSimpleReader::setContentHandler(QXmlContentHandler* handler)
3098 {
3099     Q_D(QXmlSimpleReader);
3100     d->contentHnd = handler;
3101 }
3102 
3103 /*!
3104     \reimp
3105 */
contentHandler() const3106 QXmlContentHandler* QXmlSimpleReader::contentHandler() const
3107 {
3108     const QXmlSimpleReaderPrivate *d = d_func();
3109     return d->contentHnd;
3110 }
3111 
3112 /*!
3113     \reimp
3114 */
setErrorHandler(QXmlErrorHandler * handler)3115 void QXmlSimpleReader::setErrorHandler(QXmlErrorHandler* handler)
3116 {
3117     Q_D(QXmlSimpleReader);
3118     d->errorHnd = handler;
3119 }
3120 
3121 /*!
3122     \reimp
3123 */
errorHandler() const3124 QXmlErrorHandler* QXmlSimpleReader::errorHandler() const
3125 {
3126     const QXmlSimpleReaderPrivate *d = d_func();
3127     return d->errorHnd;
3128 }
3129 
3130 /*!
3131     \reimp
3132 */
setLexicalHandler(QXmlLexicalHandler * handler)3133 void QXmlSimpleReader::setLexicalHandler(QXmlLexicalHandler* handler)
3134 {
3135     Q_D(QXmlSimpleReader);
3136     d->lexicalHnd = handler;
3137 }
3138 
3139 /*!
3140     \reimp
3141 */
lexicalHandler() const3142 QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const
3143 {
3144     const QXmlSimpleReaderPrivate *d = d_func();
3145     return d->lexicalHnd;
3146 }
3147 
3148 /*!
3149     \reimp
3150 */
setDeclHandler(QXmlDeclHandler * handler)3151 void QXmlSimpleReader::setDeclHandler(QXmlDeclHandler* handler)
3152 {
3153     Q_D(QXmlSimpleReader);
3154     d->declHnd = handler;
3155 }
3156 
3157 /*!
3158     \reimp
3159 */
declHandler() const3160 QXmlDeclHandler* QXmlSimpleReader::declHandler() const
3161 {
3162     const QXmlSimpleReaderPrivate *d = d_func();
3163     return d->declHnd;
3164 }
3165 
3166 
3167 
3168 /*!
3169     \reimp
3170 */
parse(const QXmlInputSource & input)3171 bool QXmlSimpleReader::parse(const QXmlInputSource& input)
3172 {
3173     return parse(&input, false);
3174 }
3175 
3176 /*!
3177     Reads an XML document from \a input and parses it in one pass (non-incrementally).
3178     Returns \c true if the parsing was successful; otherwise returns \c false.
3179 */
parse(const QXmlInputSource * input)3180 bool QXmlSimpleReader::parse(const QXmlInputSource* input)
3181 {
3182     return parse(input, false);
3183 }
3184 
3185 /*!
3186     Reads an XML document from \a input and parses it. Returns \c true
3187     if the parsing is completed successfully; otherwise returns \c false,
3188     indicating that an error occurred.
3189 
3190     If \a incremental is false, this function will return false if the XML
3191     file is not read completely. The parsing cannot be continued in this
3192     case.
3193 
3194     If \a incremental is true, the parser does not return false if
3195     it reaches the end of the \a input before reaching the end
3196     of the XML file. Instead, it stores the state of the parser so that
3197     parsing can be continued later when more data is available.
3198     In such a case, you can use the function parseContinue() to
3199     continue with parsing. This class stores a pointer to the input
3200     source \a input and the parseContinue() function tries to read from
3201     that input source. Therefore, you should not delete the input
3202     source \a input until you no longer need to call parseContinue().
3203 
3204     If this function is called with \a incremental set to true
3205     while an incremental parse is in progress, a new parsing
3206     session will be started, and the previous session will be lost.
3207 
3208     \sa parseContinue(), QTcpSocket
3209 */
parse(const QXmlInputSource * input,bool incremental)3210 bool QXmlSimpleReader::parse(const QXmlInputSource *input, bool incremental)
3211 {
3212     Q_D(QXmlSimpleReader);
3213 
3214     d->literalEntitySizes.clear();
3215     d->referencesToOtherEntities.clear();
3216     d->expandedSizes.clear();
3217 
3218     if (incremental) {
3219         d->initIncrementalParsing();
3220     } else {
3221         delete d->parseStack;
3222         d->parseStack = nullptr;
3223     }
3224     d->init(input);
3225 
3226     // call the handler
3227     if (d->contentHnd) {
3228         d->contentHnd->setDocumentLocator(d->locator.data());
3229         if (!d->contentHnd->startDocument()) {
3230             d->reportParseError(d->contentHnd->errorString());
3231             clear(d->tags);
3232             return false;
3233         }
3234     }
3235     d->skipped_entity_in_content = false;
3236     return d->parseBeginOrContinue(0, incremental);
3237 }
3238 
3239 /*!
3240     Continues incremental parsing, taking input from the
3241     QXmlInputSource that was specified with the most recent
3242     call to parse(). To use this function, you \e must have called
3243     parse() with the incremental argument set to true.
3244 
3245     Returns \c false if a parsing error occurs; otherwise returns \c true,
3246     even if the end of the XML file has not been reached. You can
3247     continue parsing at a later stage by calling this function again
3248     when there is more data available to parse.
3249 
3250     Calling this function when there is no data available in the input
3251     source indicates to the reader that the end of the XML file has
3252     been reached. If the input supplied up to this point was
3253     not well-formed then a parsing error occurs, and false is returned.
3254     If the input supplied was well-formed, true is returned.
3255     It is important to end the input in this way because it allows you
3256     to reuse the reader to parse other XML files.
3257 
3258     Calling this function after the end of file has been reached, but
3259     without available data will cause false to be returned whether the
3260     previous input was well-formed or not.
3261 
3262     \sa parse(), QXmlInputSource::data(), QXmlInputSource::next()
3263 */
parseContinue()3264 bool QXmlSimpleReader::parseContinue()
3265 {
3266     Q_D(QXmlSimpleReader);
3267     if (d->parseStack == nullptr || d->parseStack->isEmpty())
3268         return false;
3269     d->initData();
3270     int state = d->parseStack->pop().state;
3271     return d->parseBeginOrContinue(state, true);
3272 }
3273 
3274 /*
3275   Common part of parse() and parseContinue()
3276 */
parseBeginOrContinue(int state,bool incremental)3277 bool QXmlSimpleReaderPrivate::parseBeginOrContinue(int state, bool incremental)
3278 {
3279     bool atEndOrig = atEnd();
3280 
3281     if (state==0) {
3282         if (!parseProlog()) {
3283             if (incremental && error.isNull()) {
3284                 pushParseState(nullptr, 0);
3285                 return true;
3286             } else {
3287                 clear(tags);
3288                 return false;
3289             }
3290         }
3291         state = 1;
3292     }
3293     if (state==1) {
3294         if (!parseElement()) {
3295             if (incremental && error.isNull()) {
3296                 pushParseState(nullptr, 1);
3297                 return true;
3298             } else {
3299                 clear(tags);
3300                 return false;
3301             }
3302         }
3303         state = 2;
3304     }
3305     // parse Misc*
3306     while (!atEnd()) {
3307         if (!parseMisc()) {
3308             if (incremental && error.isNull()) {
3309                 pushParseState(nullptr, 2);
3310                 return true;
3311             } else {
3312                 clear(tags);
3313                 return false;
3314             }
3315         }
3316     }
3317     if (!atEndOrig && incremental) {
3318         // we parsed something at all, so be prepared to come back later
3319         pushParseState(nullptr, 2);
3320         return true;
3321     }
3322     // is stack empty?
3323     if (!tags.empty() && !error.isNull()) {
3324         reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
3325         clear(tags);
3326         return false;
3327     }
3328     // call the handler
3329     if (contentHnd) {
3330         delete parseStack;
3331         parseStack = nullptr;
3332         if (!contentHnd->endDocument()) {
3333             reportParseError(contentHnd->errorString());
3334             return false;
3335         }
3336     }
3337     return true;
3338 }
3339 
3340 //
3341 // The following private parse functions have another semantics for the return
3342 // value: They return true iff parsing has finished successfully (i.e. the end
3343 // of the XML file must be reached!). If one of these functions return false,
3344 // there is only an error when d->error.isNULL() is also false.
3345 //
3346 
3347 /*
3348   For the incremental parsing, it is very important that the parse...()
3349   functions have a certain structure. Since it might be hard to understand how
3350   they work, here is a description of the layout of these functions:
3351 
3352     bool QXmlSimpleReader::parse...()
3353     {
3354 (1)        const signed char Init             = 0;
3355         ...
3356 
3357 (2)        const signed char Inp...           = 0;
3358         ...
3359 
3360 (3)        static const signed char table[3][2] = {
3361         ...
3362         };
3363         signed char state;
3364         signed char input;
3365 
3366 (4)        if (d->parseStack == nullptr || d->parseStack->isEmpty()) {
3367 (4a)        ...
3368         } else {
3369 (4b)        ...
3370         }
3371 
3372         for (; ;) {
3373 (5)            switch (state) {
3374             ...
3375             }
3376 
3377 (6)
3378 (6a)            if (atEnd()) {
3379                 unexpectedEof(&QXmlSimpleReader::parseNmtoken, state);
3380                 return false;
3381             }
3382 (6b)            if (determineNameChar(c) != NotName) {
3383             ...
3384             }
3385 (7)            state = table[state][input];
3386 
3387 (8)            switch (state) {
3388             ...
3389             }
3390         }
3391     }
3392 
3393   Explanation:
3394   ad 1: constants for the states (used in the transition table)
3395   ad 2: constants for the input (used in the transition table)
3396   ad 3: the transition table for the state machine
3397   ad 4: test if we are in a parseContinue() step
3398         a) if no, do inititalizations
3399         b) if yes, restore the state and call parse functions recursively
3400   ad 5: Do some actions according to the state; from the logical execution
3401         order, this code belongs after 8 (see there for an explanation)
3402   ad 6: Check the character that is at the actual "cursor" position:
3403         a) If we reached the EOF, report either error or push the state (in the
3404            case of incremental parsing).
3405         b) Otherwise, set the input character constant for the transition
3406            table.
3407   ad 7: Get the new state according to the input that was read.
3408   ad 8: Do some actions according to the state. The last line in every case
3409         statement reads new data (i.e. it move the cursor). This can also be
3410         done by calling another parse...() function. If you need processing for
3411         this state after that, you have to put it into the switch statement 5.
3412         This ensures that you have a well defined re-entry point, when you ran
3413         out of data.
3414 */
3415 
3416 /*
3417   Parses the prolog [22].
3418 */
3419 
parseProlog()3420 bool QXmlSimpleReaderPrivate::parseProlog()
3421 {
3422     const signed char Init             = 0;
3423     const signed char EatWS            = 1; // eat white spaces
3424     const signed char Lt               = 2; // '<' read
3425     const signed char Em               = 3; // '!' read
3426     const signed char DocType          = 4; // read doctype
3427     const signed char Comment          = 5; // read comment
3428     const signed char CommentR         = 6; // same as Comment, but already reported
3429     const signed char PInstr           = 7; // read PI
3430     const signed char PInstrR          = 8; // same as PInstr, but already reported
3431     const signed char Done             = 9;
3432 
3433     const signed char InpWs            = 0;
3434     const signed char InpLt            = 1; // <
3435     const signed char InpQm            = 2; // ?
3436     const signed char InpEm            = 3; // !
3437     const signed char InpD             = 4; // D
3438     const signed char InpDash          = 5; // -
3439     const signed char InpUnknown       = 6;
3440 
3441     static const signed char table[9][7] = {
3442      /*  InpWs   InpLt  InpQm  InpEm  InpD      InpDash  InpUnknown */
3443         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // Init
3444         { -1,     Lt,    -1,    -1,    -1,       -1,       -1      }, // EatWS
3445         { -1,     -1,    PInstr,Em,    Done,     -1,       Done    }, // Lt
3446         { -1,     -1,    -1,    -1,    DocType,  Comment,  -1      }, // Em
3447         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // DocType
3448         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // Comment
3449         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // CommentR
3450         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }, // PInstr
3451         { EatWS,  Lt,    -1,    -1,    -1,       -1,       -1      }  // PInstrR
3452     };
3453     signed char state;
3454     signed char input;
3455 
3456     if (parseStack == nullptr|| parseStack->isEmpty()) {
3457         xmldecl_possible = true;
3458         doctype_read = false;
3459         state = Init;
3460     } else {
3461         state = parseStack->pop().state;
3462 #if defined(QT_QXML_DEBUG)
3463         qDebug("QXmlSimpleReader: parseProlog (cont) in state %d", state);
3464 #endif
3465         if (!parseStack->isEmpty()) {
3466             ParseFunction function = parseStack->top().function;
3467             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
3468                 parseStack->pop();
3469 #if defined(QT_QXML_DEBUG)
3470                 qDebug("QXmlSimpleReader: eat_ws (cont)");
3471 #endif
3472             }
3473             if (!(this->*function)()) {
3474                 parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
3475                 return false;
3476             }
3477         }
3478     }
3479 
3480     for (;;) {
3481         switch (state) {
3482             case DocType:
3483                 if (doctype_read) {
3484                     reportParseError(QLatin1String(XMLERR_MORETHANONEDOCTYPE));
3485                     return false;
3486                 } else {
3487                     doctype_read = false;
3488                 }
3489                 break;
3490             case Comment:
3491                 if (lexicalHnd) {
3492                     if (!lexicalHnd->comment(string())) {
3493                         reportParseError(lexicalHnd->errorString());
3494                         return false;
3495                     }
3496                 }
3497                 state = CommentR;
3498                 break;
3499             case PInstr:
3500                 // call the handler
3501                 if (contentHnd) {
3502                     if (xmldecl_possible && !xmlVersion.isEmpty()) {
3503                         QString value(QLatin1String("version='"));
3504                         value += xmlVersion;
3505                         value += QLatin1Char('\'');
3506                         if (!encoding.isEmpty()) {
3507                             value += QLatin1String(" encoding='");
3508                             value += encoding;
3509                             value += QLatin1Char('\'');
3510                         }
3511                         if (standalone == QXmlSimpleReaderPrivate::Yes) {
3512                             value += QLatin1String(" standalone='yes'");
3513                         } else if (standalone == QXmlSimpleReaderPrivate::No) {
3514                             value += QLatin1String(" standalone='no'");
3515                         }
3516                         if (!contentHnd->processingInstruction(QLatin1String("xml"), value)) {
3517                             reportParseError(contentHnd->errorString());
3518                             return false;
3519                         }
3520                     } else {
3521                         if (!contentHnd->processingInstruction(name(), string())) {
3522                             reportParseError(contentHnd->errorString());
3523                             return false;
3524                         }
3525                     }
3526                 }
3527                 // XML declaration only on first position possible
3528                 xmldecl_possible = false;
3529                 state = PInstrR;
3530                 break;
3531             case Done:
3532                 return true;
3533             case -1:
3534                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
3535                 return false;
3536         }
3537 
3538         if (atEnd()) {
3539             unexpectedEof(&QXmlSimpleReaderPrivate::parseProlog, state);
3540             return false;
3541         }
3542         if (is_S(c)) {
3543             input = InpWs;
3544         } else if (c == QLatin1Char('<')) {
3545             input = InpLt;
3546         } else if (c == QLatin1Char('?')) {
3547             input = InpQm;
3548         } else if (c == QLatin1Char('!')) {
3549             input = InpEm;
3550         } else if (c == QLatin1Char('D')) {
3551             input = InpD;
3552         } else if (c == QLatin1Char('-')) {
3553             input = InpDash;
3554         } else {
3555             input = InpUnknown;
3556         }
3557         state = table[state][input];
3558 
3559         switch (state) {
3560             case EatWS:
3561                 // XML declaration only on first position possible
3562                 xmldecl_possible = false;
3563                 if (!eat_ws()) {
3564                     parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
3565                     return false;
3566                 }
3567                 break;
3568             case Lt:
3569                 next();
3570                 break;
3571             case Em:
3572                 // XML declaration only on first position possible
3573                 xmldecl_possible = false;
3574                 next();
3575                 break;
3576             case DocType:
3577                 if (!parseDoctype()) {
3578                     parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
3579                     return false;
3580                 }
3581                 break;
3582             case Comment:
3583             case CommentR:
3584                 if (!parseComment()) {
3585                     parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
3586                     return false;
3587                 }
3588                 break;
3589             case PInstr:
3590             case PInstrR:
3591                 parsePI_xmldecl = xmldecl_possible;
3592                 if (!parsePI()) {
3593                     parseFailed(&QXmlSimpleReaderPrivate::parseProlog, state);
3594                     return false;
3595                 }
3596                 break;
3597         }
3598     }
3599     return false;
3600 }
3601 
3602 /*
3603   Parse an element [39].
3604 
3605   Precondition: the opening '<' is already read.
3606 */
parseElement()3607 bool QXmlSimpleReaderPrivate::parseElement()
3608 {
3609     const int Init             =  0;
3610     const int ReadName         =  1;
3611     const int Ws1              =  2;
3612     const int STagEnd          =  3;
3613     const int STagEnd2         =  4;
3614     const int ETagBegin        =  5;
3615     const int ETagBegin2       =  6;
3616     const int Ws2              =  7;
3617     const int EmptyTag         =  8;
3618     const int Attrib           =  9;
3619     const int AttribPro        = 10; // like Attrib, but processAttribute was already called
3620     const int Ws3              = 11;
3621     const int Done             = 12;
3622 
3623     const int InpWs            = 0; // whitespace
3624     const int InpNameBe        = 1; // NameBeginning
3625     const int InpGt            = 2; // >
3626     const int InpSlash         = 3; // /
3627     const int InpUnknown       = 4;
3628 
3629     static const int table[12][5] = {
3630      /*  InpWs      InpNameBe    InpGt        InpSlash     InpUnknown */
3631         { -1,        ReadName,    -1,          -1,          -1        }, // Init
3632         { Ws1,       Attrib,      STagEnd,     EmptyTag,    -1        }, // ReadName
3633         { -1,        Attrib,      STagEnd,     EmptyTag,    -1        }, // Ws1
3634         { STagEnd2,  STagEnd2,    STagEnd2,    STagEnd2,    STagEnd2  }, // STagEnd
3635         { -1,        -1,          -1,          ETagBegin,   -1        }, // STagEnd2
3636         { -1,        ETagBegin2,  -1,          -1,          -1        }, // ETagBegin
3637         { Ws2,       -1,          Done,        -1,          -1        }, // ETagBegin2
3638         { -1,        -1,          Done,        -1,          -1        }, // Ws2
3639         { -1,        -1,          Done,        -1,          -1        }, // EmptyTag
3640         { Ws3,       Attrib,      STagEnd,     EmptyTag,    -1        }, // Attrib
3641         { Ws3,       Attrib,      STagEnd,     EmptyTag,    -1        }, // AttribPro
3642         { -1,        Attrib,      STagEnd,     EmptyTag,    -1        }  // Ws3
3643     };
3644     int state;
3645     int input;
3646 
3647     if (parseStack == nullptr|| parseStack->isEmpty()) {
3648         state = Init;
3649     } else {
3650         state = parseStack->pop().state;
3651 #if defined(QT_QXML_DEBUG)
3652         qDebug("QXmlSimpleReader: parseElement (cont) in state %d", state);
3653 #endif
3654         if (!parseStack->isEmpty()) {
3655             ParseFunction function = parseStack->top().function;
3656             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
3657                 parseStack->pop();
3658 #if defined(QT_QXML_DEBUG)
3659                 qDebug("QXmlSimpleReader: eat_ws (cont)");
3660 #endif
3661             }
3662             if (!(this->*function)()) {
3663                 parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3664                 return false;
3665             }
3666         }
3667     }
3668 
3669     for (;;) {
3670         switch (state) {
3671             case ReadName:
3672                 // store it on the stack
3673                 tags.push(name());
3674                 // empty the attributes
3675                 attList.clear();
3676                 if (useNamespaces)
3677                     namespaceSupport.pushContext();
3678                 break;
3679             case ETagBegin2:
3680                 if (!processElementETagBegin2())
3681                     return false;
3682                 break;
3683             case Attrib:
3684                 if (!processElementAttribute())
3685                     return false;
3686                 state = AttribPro;
3687                 break;
3688             case Done:
3689                 return true;
3690             case -1:
3691                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGELEMENT));
3692                 return false;
3693         }
3694 
3695         if (atEnd()) {
3696             unexpectedEof(&QXmlSimpleReaderPrivate::parseElement, state);
3697             return false;
3698         }
3699         if (fastDetermineNameChar(c) == NameBeginning) {
3700             input = InpNameBe;
3701         } else if (c == QLatin1Char('>')) {
3702             input = InpGt;
3703         } else if (is_S(c)) {
3704             input = InpWs;
3705         } else if (c == QLatin1Char('/')) {
3706             input = InpSlash;
3707         } else {
3708             input = InpUnknown;
3709         }
3710         state = table[state][input];
3711 
3712         switch (state) {
3713             case ReadName:
3714                 parseName_useRef = false;
3715                 if (!parseName()) {
3716                     parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3717                     return false;
3718                 }
3719                 break;
3720             case Ws1:
3721             case Ws2:
3722             case Ws3:
3723                 if (!eat_ws()) {
3724                     parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3725                     return false;
3726                 }
3727                 break;
3728             case STagEnd:
3729                 // call the handler
3730                 if (contentHnd) {
3731                     if (useNamespaces) {
3732                         QString uri, lname;
3733                         namespaceSupport.processName(tags.top(), false, uri, lname);
3734                         if (!contentHnd->startElement(uri, lname, tags.top(), attList)) {
3735                             reportParseError(contentHnd->errorString());
3736                             return false;
3737                         }
3738                     } else {
3739                         if (!contentHnd->startElement(QString(), QString(), tags.top(), attList)) {
3740                             reportParseError(contentHnd->errorString());
3741                             return false;
3742                         }
3743                     }
3744                 }
3745                 next();
3746                 break;
3747             case STagEnd2:
3748                 if (!parseContent()) {
3749                     parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3750                     return false;
3751                 }
3752                 break;
3753             case ETagBegin:
3754                 next();
3755                 break;
3756             case ETagBegin2:
3757                 // get the name of the tag
3758                 parseName_useRef = false;
3759                 if (!parseName()) {
3760                     parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3761                     return false;
3762                 }
3763                 break;
3764             case EmptyTag:
3765                 if (tags.empty()) {
3766                     reportParseError(QLatin1String(XMLERR_TAGMISMATCH));
3767                     return false;
3768                 }
3769                 if (!processElementEmptyTag())
3770                     return false;
3771                 next();
3772                 break;
3773             case Attrib:
3774             case AttribPro:
3775                 // get name and value of attribute
3776                 if (!parseAttribute()) {
3777                     parseFailed(&QXmlSimpleReaderPrivate::parseElement, state);
3778                     return false;
3779                 }
3780                 break;
3781             case Done:
3782                 next();
3783                 break;
3784         }
3785     }
3786     return false;
3787 }
3788 
3789 /*
3790   Helper to break down the size of the code in the case statement.
3791   Return false on error, otherwise true.
3792 */
processElementEmptyTag()3793 bool QXmlSimpleReaderPrivate::processElementEmptyTag()
3794 {
3795     QString uri, lname;
3796     // pop the stack and call the handler
3797     if (contentHnd) {
3798         if (useNamespaces) {
3799             // report startElement first...
3800             namespaceSupport.processName(tags.top(), false, uri, lname);
3801             if (!contentHnd->startElement(uri, lname, tags.top(), attList)) {
3802                 reportParseError(contentHnd->errorString());
3803                 return false;
3804             }
3805             // ... followed by endElement...
3806             const bool endElementReturnedFalse = !contentHnd->endElement(uri, lname, tags.top());
3807             tags.pop();
3808             if (endElementReturnedFalse) {
3809                 reportParseError(contentHnd->errorString());
3810                 return false;
3811             }
3812             // ... followed by endPrefixMapping
3813             QStringList prefixesBefore, prefixesAfter;
3814             if (contentHnd) {
3815                 prefixesBefore = namespaceSupport.prefixes();
3816             }
3817             namespaceSupport.popContext();
3818             // call the handler for prefix mapping
3819             prefixesAfter = namespaceSupport.prefixes();
3820             for (QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it) {
3821                 if (!prefixesAfter.contains(*it)) {
3822                     if (!contentHnd->endPrefixMapping(*it)) {
3823                         reportParseError(contentHnd->errorString());
3824                         return false;
3825                     }
3826                 }
3827             }
3828         } else {
3829             // report startElement first...
3830             if (!contentHnd->startElement(QString(), QString(), tags.top(), attList)) {
3831                 reportParseError(contentHnd->errorString());
3832                 return false;
3833             }
3834             // ... followed by endElement
3835             const bool endElementReturnedFalse = !contentHnd->endElement(QString(), QString(), tags.top());
3836             tags.pop();
3837             if (endElementReturnedFalse) {
3838                 reportParseError(contentHnd->errorString());
3839                 return false;
3840             }
3841         }
3842     } else {
3843         tags.pop();
3844         namespaceSupport.popContext();
3845     }
3846     return true;
3847 }
3848 /*
3849   Helper to break down the size of the code in the case statement.
3850   Return false on error, otherwise true.
3851 */
processElementETagBegin2()3852 bool QXmlSimpleReaderPrivate::processElementETagBegin2()
3853 {
3854     const QString &name = QXmlSimpleReaderPrivate::name();
3855 
3856     // pop the stack and compare it with the name
3857     const bool nameIsTagsTop = tags.top() == name;
3858     tags.pop();
3859     if (!nameIsTagsTop) {
3860         reportParseError(QLatin1String(XMLERR_TAGMISMATCH));
3861         return false;
3862     }
3863     // call the handler
3864     if (contentHnd) {
3865         QString uri, lname;
3866 
3867         if (useNamespaces)
3868             namespaceSupport.processName(name, false, uri, lname);
3869         if (!contentHnd->endElement(uri, lname, name)) {
3870             reportParseError(contentHnd->errorString());
3871             return false;
3872         }
3873     }
3874     if (useNamespaces) {
3875         NamespaceMap prefixesBefore, prefixesAfter;
3876         if (contentHnd)
3877             prefixesBefore = namespaceSupport.d->ns;
3878 
3879         namespaceSupport.popContext();
3880         // call the handler for prefix mapping
3881         if (contentHnd) {
3882             prefixesAfter = namespaceSupport.d->ns;
3883             if (prefixesBefore.size() != prefixesAfter.size()) {
3884                 for (NamespaceMap::const_iterator it = prefixesBefore.constBegin(); it != prefixesBefore.constEnd(); ++it) {
3885                     if (!it.key().isEmpty() && !prefixesAfter.contains(it.key())) {
3886                         if (!contentHnd->endPrefixMapping(it.key())) {
3887                             reportParseError(contentHnd->errorString());
3888                             return false;
3889                         }
3890                     }
3891                 }
3892             }
3893         }
3894     }
3895     return true;
3896 }
3897 /*
3898   Helper to break down the size of the code in the case statement.
3899   Return false on error, otherwise true.
3900 */
processElementAttribute()3901 bool QXmlSimpleReaderPrivate::processElementAttribute()
3902 {
3903     QString uri, lname, prefix;
3904     const QString &name = QXmlSimpleReaderPrivate::name();
3905     const QString &string = QXmlSimpleReaderPrivate::string();
3906 
3907     // add the attribute to the list
3908     if (useNamespaces) {
3909         // is it a namespace declaration?
3910         namespaceSupport.splitName(name, prefix, lname);
3911         if (prefix == QLatin1String("xmlns")) {
3912             // namespace declaration
3913             namespaceSupport.setPrefix(lname, string);
3914             if (useNamespacePrefixes) {
3915                 // according to http://www.w3.org/2000/xmlns/, the "prefix"
3916                 // xmlns maps to the namespace name
3917                 // http://www.w3.org/2000/xmlns/
3918                 attList.append(name, QLatin1String("http://www.w3.org/2000/xmlns/"), lname, string);
3919             }
3920             // call the handler for prefix mapping
3921             if (contentHnd) {
3922                 if (!contentHnd->startPrefixMapping(lname, string)) {
3923                     reportParseError(contentHnd->errorString());
3924                     return false;
3925                 }
3926             }
3927         } else {
3928             // no namespace delcaration
3929             namespaceSupport.processName(name, true, uri, lname);
3930             attList.append(name, uri, lname, string);
3931         }
3932     } else {
3933         // no namespace support
3934         attList.append(name, uri, lname, string);
3935     }
3936     return true;
3937 }
3938 
3939 /*
3940   Parse a content [43].
3941 
3942   A content is only used between tags. If a end tag is found the < is already
3943   read and the head stand on the '/' of the end tag '</name>'.
3944 */
parseContent()3945 bool QXmlSimpleReaderPrivate::parseContent()
3946 {
3947     const signed char Init             =  0;
3948     const signed char ChD              =  1; // CharData
3949     const signed char ChD1             =  2; // CharData help state
3950     const signed char ChD2             =  3; // CharData help state
3951     const signed char Ref              =  4; // Reference
3952     const signed char Lt               =  5; // '<' read
3953     const signed char PInstr           =  6; // PI
3954     const signed char PInstrR          =  7; // same as PInstr, but already reported
3955     const signed char Elem             =  8; // Element
3956     const signed char Em               =  9; // '!' read
3957     const signed char Com              = 10; // Comment
3958     const signed char ComR             = 11; // same as Com, but already reported
3959     const signed char CDS              = 12; // CDSect
3960     const signed char CDS1             = 13; // read a CDSect
3961     const signed char CDS2             = 14; // read a CDSect (help state)
3962     const signed char CDS3             = 15; // read a CDSect (help state)
3963     const signed char Done             = 16; // finished reading content
3964 
3965     const signed char InpLt            = 0; // <
3966     const signed char InpGt            = 1; // >
3967     const signed char InpSlash         = 2; // /
3968     const signed char InpQMark         = 3; // ?
3969     const signed char InpEMark         = 4; // !
3970     const signed char InpAmp           = 5; // &
3971     const signed char InpDash          = 6; // -
3972     const signed char InpOpenB         = 7; // [
3973     const signed char InpCloseB        = 8; //]
3974     const signed char InpUnknown       = 9;
3975 
3976     static const signed char mapCLT2FSMChar[] = {
3977         InpUnknown, // white space
3978         InpUnknown, // %
3979         InpAmp,     // &
3980         InpGt,      // >
3981         InpLt,      // <
3982         InpSlash,   // /
3983         InpQMark,   // ?
3984         InpEMark,   // !
3985         InpDash,    // -
3986         InpCloseB,  //]
3987         InpOpenB,   // [
3988         InpUnknown, // =
3989         InpUnknown, // "
3990         InpUnknown, // '
3991         InpUnknown  // unknown
3992     };
3993 
3994     static const signed char table[16][10] = {
3995      /*  InpLt  InpGt  InpSlash  InpQMark  InpEMark  InpAmp  InpDash  InpOpenB  InpCloseB  InpUnknown */
3996         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD1,      ChD  }, // Init
3997         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD1,      ChD  }, // ChD
3998         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD2,      ChD  }, // ChD1
3999         { Lt,    -1,    ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD2,      ChD  }, // ChD2
4000         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Ref (same as Init)
4001         { -1,    -1,    Done,     PInstr,   Em,       -1,     -1,      -1,       -1,        Elem }, // Lt
4002         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // PInstr (same as Init)
4003         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // PInstrR
4004         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Elem (same as Init)
4005         { -1,    -1,    -1,       -1,       -1,       -1,     Com,     CDS,      -1,        -1   }, // Em
4006         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // Com (same as Init)
4007         { Lt,    ChD,   ChD,      ChD,      ChD,      Ref,    ChD,     ChD,      ChD,       ChD  }, // ComR
4008         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS2,      CDS1 }, // CDS
4009         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS2,      CDS1 }, // CDS1
4010         { CDS1,  CDS1,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS3,      CDS1 }, // CDS2
4011         { CDS1,  Init,  CDS1,     CDS1,     CDS1,     CDS1,   CDS1,    CDS1,     CDS3,      CDS1 }  // CDS3
4012     };
4013     signed char state;
4014     signed char input;
4015 
4016     if (parseStack == nullptr || parseStack->isEmpty()) {
4017         contentCharDataRead = false;
4018         state = Init;
4019     } else {
4020         state = parseStack->pop().state;
4021 #if defined(QT_QXML_DEBUG)
4022         qDebug("QXmlSimpleReader: parseContent (cont) in state %d", state);
4023 #endif
4024         if (!parseStack->isEmpty()) {
4025             ParseFunction function = parseStack->top().function;
4026             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
4027                 parseStack->pop();
4028 #if defined(QT_QXML_DEBUG)
4029                 qDebug("QXmlSimpleReader: eat_ws (cont)");
4030 #endif
4031             }
4032             if (!(this->*function)()) {
4033                 parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4034                 return false;
4035             }
4036         }
4037     }
4038 
4039     for (;;) {
4040         switch (state) {
4041             case Ref:
4042                 if (!contentCharDataRead)
4043                     contentCharDataRead = parseReference_charDataRead;
4044                 break;
4045             case PInstr:
4046                 if (contentHnd) {
4047                     if (!contentHnd->processingInstruction(name(),string())) {
4048                         reportParseError(contentHnd->errorString());
4049                         return false;
4050                     }
4051                 }
4052                 state = PInstrR;
4053                 break;
4054             case Com:
4055                 if (lexicalHnd) {
4056                     if (!lexicalHnd->comment(string())) {
4057                         reportParseError(lexicalHnd->errorString());
4058                         return false;
4059                     }
4060                 }
4061                 state = ComR;
4062                 break;
4063             case CDS:
4064                 stringClear();
4065                 break;
4066             case CDS2:
4067                 if (!atEnd() && c != QLatin1Char(']'))
4068                     stringAddC(QLatin1Char(']'));
4069                 break;
4070             case CDS3:
4071                 // test if this skipping was legal
4072                 if (!atEnd()) {
4073                     if (c == QLatin1Char('>')) {
4074                         // the end of the CDSect
4075                         if (lexicalHnd) {
4076                             if (!lexicalHnd->startCDATA()) {
4077                                 reportParseError(lexicalHnd->errorString());
4078                                 return false;
4079                             }
4080                         }
4081                         if (contentHnd) {
4082                             if (!contentHnd->characters(string())) {
4083                                 reportParseError(contentHnd->errorString());
4084                                 return false;
4085                             }
4086                         }
4087                         if (lexicalHnd) {
4088                             if (!lexicalHnd->endCDATA()) {
4089                                 reportParseError(lexicalHnd->errorString());
4090                                 return false;
4091                             }
4092                         }
4093                     } else if (c == QLatin1Char(']')) {
4094                         // three or more ']'
4095                         stringAddC(QLatin1Char(']'));
4096                     } else {
4097                         // after ']]' comes another character
4098                         stringAddC(QLatin1Char(']'));
4099                         stringAddC(QLatin1Char(']'));
4100                     }
4101                 }
4102                 break;
4103             case Done:
4104                 // call the handler for CharData
4105                 if (contentHnd) {
4106                     if (contentCharDataRead) {
4107                         if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
4108                             if (!contentHnd->characters(string())) {
4109                                 reportParseError(contentHnd->errorString());
4110                                 return false;
4111                             }
4112                         }
4113                     }
4114                 }
4115                 // Done
4116                 return true;
4117             case -1:
4118                 // Error
4119                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGCONTENT));
4120                 return false;
4121         }
4122 
4123         // get input (use lookup-table instead of nested ifs for performance
4124         // reasons)
4125         if (atEnd()) {
4126             unexpectedEof(&QXmlSimpleReaderPrivate::parseContent, state);
4127             return false;
4128         }
4129         if (c.row()) {
4130             input = InpUnknown;
4131         } else {
4132             input = mapCLT2FSMChar[charLookupTable[c.cell()]];
4133         }
4134         state = table[state][input];
4135 
4136         switch (state) {
4137             case Init:
4138                 // skip the ending '>' of a CDATASection
4139                 next();
4140                 break;
4141             case ChD:
4142                 // on first call: clear string
4143                 if (!contentCharDataRead) {
4144                     contentCharDataRead = true;
4145                     stringClear();
4146                 }
4147                 stringAddC();
4148                 if (reportEntities) {
4149                     if (!reportEndEntities())
4150                         return false;
4151                 }
4152                 next();
4153                 break;
4154             case ChD1:
4155                 // on first call: clear string
4156                 if (!contentCharDataRead) {
4157                     contentCharDataRead = true;
4158                     stringClear();
4159                 }
4160                 stringAddC();
4161                 if (reportEntities) {
4162                     if (!reportEndEntities())
4163                         return false;
4164                 }
4165                 next();
4166                 break;
4167             case ChD2:
4168                 stringAddC();
4169                 if (reportEntities) {
4170                     if (!reportEndEntities())
4171                         return false;
4172                 }
4173                 next();
4174                 break;
4175             case Ref:
4176                 if (!contentCharDataRead) {
4177                     // reference may be CharData; so clear string to be safe
4178                     stringClear();
4179                     parseReference_context = InContent;
4180                     if (!parseReference()) {
4181                         parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4182                         return false;
4183                     }
4184                 } else {
4185                     if (reportEntities) {
4186                         // report character data in chunks
4187                         if (contentHnd) {
4188                             if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
4189                                 if (!contentHnd->characters(string())) {
4190                                     reportParseError(contentHnd->errorString());
4191                                     return false;
4192                                 }
4193                             }
4194                         }
4195                         stringClear();
4196                     }
4197                     parseReference_context = InContent;
4198                     if (!parseReference()) {
4199                         parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4200                         return false;
4201                     }
4202                 }
4203                 break;
4204             case Lt:
4205                 // call the handler for CharData
4206                 if (contentHnd) {
4207                     if (contentCharDataRead) {
4208                         if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
4209                             if (!contentHnd->characters(string())) {
4210                                 reportParseError(contentHnd->errorString());
4211                                 return false;
4212                             }
4213                         }
4214                     }
4215                 }
4216                 contentCharDataRead = false;
4217                 next();
4218                 break;
4219             case PInstr:
4220             case PInstrR:
4221                 parsePI_xmldecl = false;
4222                 if (!parsePI()) {
4223                     parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4224                     return false;
4225                 }
4226                 break;
4227             case Elem:
4228                 if (!parseElement()) {
4229                     parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4230                     return false;
4231                 }
4232                 break;
4233             case Em:
4234                 next();
4235                 break;
4236             case Com:
4237             case ComR:
4238                 if (!parseComment()) {
4239                     parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4240                     return false;
4241                 }
4242                 break;
4243             case CDS:
4244                 parseString_s = QLatin1String("[CDATA[");
4245                 if (!parseString()) {
4246                     parseFailed(&QXmlSimpleReaderPrivate::parseContent, state);
4247                     return false;
4248                 }
4249                 break;
4250             case CDS1:
4251                 stringAddC();
4252                 next();
4253                 break;
4254             case CDS2:
4255                 // skip ']'
4256                 next();
4257                 break;
4258             case CDS3:
4259                 // skip ']'...
4260                 next();
4261                 break;
4262         }
4263     }
4264     return false;
4265 }
4266 
reportEndEntities()4267 bool QXmlSimpleReaderPrivate::reportEndEntities()
4268 {
4269     int count = (int)xmlRefStack.count();
4270     while (count != 0 && xmlRefStack.top().isEmpty()) {
4271         if (contentHnd) {
4272             if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
4273                 if (!contentHnd->characters(string())) {
4274                     reportParseError(contentHnd->errorString());
4275                     return false;
4276                 }
4277             }
4278         }
4279         stringClear();
4280         if (lexicalHnd) {
4281             if (!lexicalHnd->endEntity(xmlRefStack.top().name)) {
4282                 reportParseError(lexicalHnd->errorString());
4283                 return false;
4284             }
4285         }
4286         xmlRefStack.pop_back();
4287         count--;
4288     }
4289     return true;
4290 }
4291 
4292 /*
4293   Parse Misc [27].
4294 */
parseMisc()4295 bool QXmlSimpleReaderPrivate::parseMisc()
4296 {
4297     const signed char Init             = 0;
4298     const signed char Lt               = 1; // '<' was read
4299     const signed char Comment          = 2; // read comment
4300     const signed char eatWS            = 3; // eat whitespaces
4301     const signed char PInstr           = 4; // read PI
4302     const signed char Comment2         = 5; // read comment
4303 
4304     const signed char InpWs            = 0; // S
4305     const signed char InpLt            = 1; // <
4306     const signed char InpQm            = 2; // ?
4307     const signed char InpEm            = 3; // !
4308     const signed char InpUnknown       = 4;
4309 
4310     static const signed char table[3][5] = {
4311      /*  InpWs   InpLt  InpQm  InpEm     InpUnknown */
4312         { eatWS,  Lt,    -1,    -1,       -1        }, // Init
4313         { -1,     -1,    PInstr,Comment,  -1        }, // Lt
4314         { -1,     -1,    -1,    -1,       Comment2  }  // Comment
4315     };
4316     signed char state;
4317     signed char input;
4318 
4319     if (parseStack == nullptr || parseStack->isEmpty()) {
4320         state = Init;
4321     } else {
4322         state = parseStack->pop().state;
4323 #if defined(QT_QXML_DEBUG)
4324         qDebug("QXmlSimpleReader: parseMisc (cont) in state %d", state);
4325 #endif
4326         if (!parseStack->isEmpty()) {
4327             ParseFunction function = parseStack->top().function;
4328             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
4329                 parseStack->pop();
4330 #if defined(QT_QXML_DEBUG)
4331                 qDebug("QXmlSimpleReader: eat_ws (cont)");
4332 #endif
4333             }
4334             if (!(this->*function)()) {
4335                 parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
4336                 return false;
4337             }
4338         }
4339     }
4340 
4341     for (;;) {
4342         switch (state) {
4343             case eatWS:
4344                 return true;
4345             case PInstr:
4346                 if (contentHnd) {
4347                     if (!contentHnd->processingInstruction(name(),string())) {
4348                         reportParseError(contentHnd->errorString());
4349                         return false;
4350                     }
4351                 }
4352                 return true;
4353             case Comment2:
4354                 if (lexicalHnd) {
4355                     if (!lexicalHnd->comment(string())) {
4356                         reportParseError(lexicalHnd->errorString());
4357                         return false;
4358                     }
4359                 }
4360                 return true;
4361             case -1:
4362                 // Error
4363                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
4364                 return false;
4365         }
4366 
4367         if (atEnd()) {
4368             unexpectedEof(&QXmlSimpleReaderPrivate::parseMisc, state);
4369             return false;
4370         }
4371         if (is_S(c)) {
4372             input = InpWs;
4373         } else if (c == QLatin1Char('<')) {
4374             input = InpLt;
4375         } else if (c == QLatin1Char('?')) {
4376             input = InpQm;
4377         } else if (c == QLatin1Char('!')) {
4378             input = InpEm;
4379         } else {
4380             input = InpUnknown;
4381         }
4382         state = table[state][input];
4383 
4384         switch (state) {
4385             case eatWS:
4386                 if (!eat_ws()) {
4387                     parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
4388                     return false;
4389                 }
4390                 break;
4391             case Lt:
4392                 next();
4393                 break;
4394             case PInstr:
4395                 parsePI_xmldecl = false;
4396                 if (!parsePI()) {
4397                     parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
4398                     return false;
4399                 }
4400                 break;
4401             case Comment:
4402                 next();
4403                 break;
4404             case Comment2:
4405                 if (!parseComment()) {
4406                     parseFailed(&QXmlSimpleReaderPrivate::parseMisc, state);
4407                     return false;
4408                 }
4409                 break;
4410         }
4411     }
4412     return false;
4413 }
4414 
4415 /*
4416   Parse a processing instruction [16].
4417 
4418   If xmldec is true, it tries to parse a PI or a XML declaration [23].
4419 
4420   Precondition: the beginning '<' of the PI is already read and the head stand
4421   on the '?' of '<?'.
4422 
4423   If this funktion was successful, the head-position is on the first
4424   character after the PI.
4425 */
parsePI()4426 bool QXmlSimpleReaderPrivate::parsePI()
4427 {
4428     const signed char Init             =  0;
4429     const signed char QmI              =  1; // ? was read
4430     const signed char Name             =  2; // read Name
4431     const signed char XMLDecl          =  3; // read XMLDecl
4432     const signed char Ws1              =  4; // eat ws after "xml" of XMLDecl
4433     const signed char PInstr           =  5; // read PI
4434     const signed char Ws2              =  6; // eat ws after Name of PI
4435     const signed char Version          =  7; // read versionInfo
4436     const signed char Ws3              =  8; // eat ws after versionInfo
4437     const signed char EorSD            =  9; // read EDecl or SDDecl
4438     const signed char Ws4              = 10; // eat ws after EDecl or SDDecl
4439     const signed char SD               = 11; // read SDDecl
4440     const signed char Ws5              = 12; // eat ws after SDDecl
4441     const signed char ADone            = 13; // almost done
4442     const signed char Char             = 14; // Char was read
4443     const signed char Qm               = 15; // Qm was read
4444     const signed char Done             = 16; // finished reading content
4445 
4446     const signed char InpWs            = 0; // whitespace
4447     const signed char InpNameBe        = 1; // NameBeginning
4448     const signed char InpGt            = 2; // >
4449     const signed char InpQm            = 3; // ?
4450     const signed char InpUnknown       = 4;
4451 
4452     static const signed char table[16][5] = {
4453      /*  InpWs,  InpNameBe  InpGt  InpQm   InpUnknown  */
4454         { -1,     -1,        -1,    QmI,    -1     }, // Init
4455         { -1,     Name,      -1,    -1,     -1     }, // QmI
4456         { -1,     -1,        -1,    -1,     -1     }, // Name (this state is left not through input)
4457         { Ws1,    -1,        -1,    -1,     -1     }, // XMLDecl
4458         { -1,     Version,   -1,    -1,     -1     }, // Ws1
4459         { Ws2,    -1,        -1,    Qm,     -1     }, // PInstr
4460         { Char,   Char,      Char,  Qm,     Char   }, // Ws2
4461         { Ws3,    -1,        -1,    ADone,  -1     }, // Version
4462         { -1,     EorSD,     -1,    ADone,  -1     }, // Ws3
4463         { Ws4,    -1,        -1,    ADone,  -1     }, // EorSD
4464         { -1,     SD,        -1,    ADone,  -1     }, // Ws4
4465         { Ws5,    -1,        -1,    ADone,  -1     }, // SD
4466         { -1,     -1,        -1,    ADone,  -1     }, // Ws5
4467         { -1,     -1,        Done,  -1,     -1     }, // ADone
4468         { Char,   Char,      Char,  Qm,     Char   }, // Char
4469         { Char,   Char,      Done,  Qm,     Char   }, // Qm
4470     };
4471     signed char state;
4472     signed char input;
4473 
4474     if (parseStack == nullptr || parseStack->isEmpty()) {
4475         state = Init;
4476     } else {
4477         state = parseStack->pop().state;
4478 #if defined(QT_QXML_DEBUG)
4479         qDebug("QXmlSimpleReader: parsePI (cont) in state %d", state);
4480 #endif
4481         if (!parseStack->isEmpty()) {
4482             ParseFunction function = parseStack->top().function;
4483             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
4484                 parseStack->pop();
4485 #if defined(QT_QXML_DEBUG)
4486                 qDebug("QXmlSimpleReader: eat_ws (cont)");
4487 #endif
4488             }
4489             if (!(this->*function)()) {
4490                 parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4491                 return false;
4492             }
4493         }
4494     }
4495 
4496     for (;;) {
4497         switch (state) {
4498             case Name:
4499                 // test what name was read and determine the next state
4500                 // (not very beautiful, I admit)
4501                 if (name().toLower() == QLatin1String("xml")) {
4502                     if (parsePI_xmldecl && name() == QLatin1String("xml")) {
4503                         state = XMLDecl;
4504                     } else {
4505                         reportParseError(QLatin1String(XMLERR_INVALIDNAMEFORPI));
4506                         return false;
4507                     }
4508                 } else {
4509                     state = PInstr;
4510                     stringClear();
4511                 }
4512                 break;
4513             case Version:
4514                 // get version (syntax like an attribute)
4515                 if (name() != QLatin1String("version")) {
4516                     reportParseError(QLatin1String(XMLERR_VERSIONEXPECTED));
4517                     return false;
4518                 }
4519                 xmlVersion = string();
4520                 break;
4521             case EorSD:
4522                 // get the EDecl or SDDecl (syntax like an attribute)
4523                 if (name() == QLatin1String("standalone")) {
4524                     if (string()== QLatin1String("yes")) {
4525                         standalone = QXmlSimpleReaderPrivate::Yes;
4526                     } else if (string() == QLatin1String("no")) {
4527                         standalone = QXmlSimpleReaderPrivate::No;
4528                     } else {
4529                         reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL));
4530                         return false;
4531                     }
4532                 } else if (name() == QLatin1String("encoding")) {
4533                     encoding = string();
4534                 } else {
4535                     reportParseError(QLatin1String(XMLERR_EDECLORSDDECLEXPECTED));
4536                     return false;
4537                 }
4538                 break;
4539             case SD:
4540                 if (name() != QLatin1String("standalone")) {
4541                     reportParseError(QLatin1String(XMLERR_SDDECLEXPECTED));
4542                     return false;
4543                 }
4544                 if (string() == QLatin1String("yes")) {
4545                     standalone = QXmlSimpleReaderPrivate::Yes;
4546                 } else if (string() == QLatin1String("no")) {
4547                     standalone = QXmlSimpleReaderPrivate::No;
4548                 } else {
4549                     reportParseError(QLatin1String(XMLERR_WRONGVALUEFORSDECL));
4550                     return false;
4551                 }
4552                 break;
4553             case Qm:
4554                 // test if the skipping was legal
4555                 if (!atEnd() && c != QLatin1Char('>'))
4556                     stringAddC(QLatin1Char('?'));
4557                 break;
4558             case Done:
4559                 return true;
4560             case -1:
4561                 // Error
4562                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
4563                 return false;
4564         }
4565 
4566         if (atEnd()) {
4567             unexpectedEof(&QXmlSimpleReaderPrivate::parsePI, state);
4568             return false;
4569         }
4570         if (is_S(c)) {
4571             input = InpWs;
4572         } else if (determineNameChar(c) == NameBeginning) {
4573             input = InpNameBe;
4574         } else if (c == QLatin1Char('>')) {
4575             input = InpGt;
4576         } else if (c == QLatin1Char('?')) {
4577             input = InpQm;
4578         } else {
4579             input = InpUnknown;
4580         }
4581         state = table[state][input];
4582 
4583         switch (state) {
4584             case QmI:
4585                 next();
4586                 break;
4587             case Name:
4588                 parseName_useRef = false;
4589                 if (!parseName()) {
4590                     parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4591                     return false;
4592                 }
4593                 break;
4594             case Ws1:
4595             case Ws2:
4596             case Ws3:
4597             case Ws4:
4598             case Ws5:
4599                 if (!eat_ws()) {
4600                     parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4601                     return false;
4602                 }
4603                 break;
4604             case Version:
4605                 if (!parseAttribute()) {
4606                     parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4607                     return false;
4608                 }
4609                 break;
4610             case EorSD:
4611                 if (!parseAttribute()) {
4612                     parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4613                     return false;
4614                 }
4615                 break;
4616             case SD:
4617                 // get the SDDecl (syntax like an attribute)
4618                 if (standalone != QXmlSimpleReaderPrivate::Unknown) {
4619                     // already parsed the standalone declaration
4620                     reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
4621                     return false;
4622                 }
4623                 if (!parseAttribute()) {
4624                     parseFailed(&QXmlSimpleReaderPrivate::parsePI, state);
4625                     return false;
4626                 }
4627                 break;
4628             case ADone:
4629                 next();
4630                 break;
4631             case Char:
4632                 stringAddC();
4633                 next();
4634                 break;
4635             case Qm:
4636                 // skip the '?'
4637                 next();
4638                 break;
4639             case Done:
4640                 next();
4641                 break;
4642         }
4643     }
4644     return false;
4645 }
4646 
4647 /*
4648   Parse a document type definition (doctypedecl [28]).
4649 
4650   Precondition: the beginning '<!' of the doctype is already read the head
4651   stands on the 'D' of '<!DOCTYPE'.
4652 
4653   If this function was successful, the head-position is on the first
4654   character after the document type definition.
4655 */
parseDoctype()4656 bool QXmlSimpleReaderPrivate::parseDoctype()
4657 {
4658     const signed char Init             =  0;
4659     const signed char Doctype          =  1; // read the doctype
4660     const signed char Ws1              =  2; // eat_ws
4661     const signed char Doctype2         =  3; // read the doctype, part 2
4662     const signed char Ws2              =  4; // eat_ws
4663     const signed char Sys              =  5; // read SYSTEM or PUBLIC
4664     const signed char Ws3              =  6; // eat_ws
4665     const signed char MP               =  7; // markupdecl or PEReference
4666     const signed char MPR              =  8; // same as MP, but already reported
4667     const signed char PER              =  9; // PERReference
4668     const signed char Mup              = 10; // markupdecl
4669     const signed char Ws4              = 11; // eat_ws
4670     const signed char MPE              = 12; // end of markupdecl or PEReference
4671     const signed char Done             = 13;
4672 
4673     const signed char InpWs            = 0;
4674     const signed char InpD             = 1; // 'D'
4675     const signed char InpS             = 2; // 'S' or 'P'
4676     const signed char InpOB            = 3; // [
4677     const signed char InpCB            = 4; //]
4678     const signed char InpPer           = 5; // %
4679     const signed char InpGt            = 6; // >
4680     const signed char InpUnknown       = 7;
4681 
4682     static const signed char table[13][8] = {
4683      /*  InpWs,  InpD       InpS       InpOB  InpCB  InpPer InpGt  InpUnknown */
4684         { -1,     Doctype,   -1,        -1,    -1,    -1,    -1,    -1        }, // Init
4685         { Ws1,    -1,        -1,        -1,    -1,    -1,    -1,    -1        }, // Doctype
4686         { -1,     Doctype2,  Doctype2,  -1,    -1,    -1,    -1,    Doctype2  }, // Ws1
4687         { Ws2,    -1,        Sys,       MP,    -1,    -1,    Done,  -1        }, // Doctype2
4688         { -1,     -1,        Sys,       MP,    -1,    -1,    Done,  -1        }, // Ws2
4689         { Ws3,    -1,        -1,        MP,    -1,    -1,    Done,  -1        }, // Sys
4690         { -1,     -1,        -1,        MP,    -1,    -1,    Done,  -1        }, // Ws3
4691         { -1,     -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // MP
4692         { -1,     -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // MPR
4693         { Ws4,    -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // PER
4694         { Ws4,    -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // Mup
4695         { -1,     -1,        -1,        -1,    MPE,   PER,   -1,    Mup       }, // Ws4
4696         { -1,     -1,        -1,        -1,    -1,    -1,    Done,  -1        }  // MPE
4697     };
4698     signed char state;
4699     signed char input;
4700 
4701     if (parseStack == nullptr || parseStack->isEmpty()) {
4702         startDTDwasReported = false;
4703         systemId.clear();
4704         publicId.clear();
4705         state = Init;
4706     } else {
4707         state = parseStack->pop().state;
4708 #if defined(QT_QXML_DEBUG)
4709         qDebug("QXmlSimpleReader: parseDoctype (cont) in state %d", state);
4710 #endif
4711         if (!parseStack->isEmpty()) {
4712             ParseFunction function = parseStack->top().function;
4713             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
4714                 parseStack->pop();
4715 #if defined(QT_QXML_DEBUG)
4716                 qDebug("QXmlSimpleReader: eat_ws (cont)");
4717 #endif
4718             }
4719             if (!(this->*function)()) {
4720                 parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4721                 return false;
4722             }
4723         }
4724     }
4725 
4726     for (;;) {
4727         switch (state) {
4728             case Doctype2:
4729                 doctype = name();
4730                 break;
4731             case MP:
4732                 if (!startDTDwasReported && lexicalHnd ) {
4733                     startDTDwasReported = true;
4734                     if (!lexicalHnd->startDTD(doctype, publicId, systemId)) {
4735                         reportParseError(lexicalHnd->errorString());
4736                         return false;
4737                     }
4738                 }
4739                 state = MPR;
4740                 break;
4741             case Done:
4742                 return true;
4743             case -1:
4744                 // Error
4745                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGDOCTYPE));
4746                 return false;
4747         }
4748 
4749         if (atEnd()) {
4750             unexpectedEof(&QXmlSimpleReaderPrivate::parseDoctype, state);
4751             return false;
4752         }
4753         if (is_S(c)) {
4754             input = InpWs;
4755         } else if (c == QLatin1Char('D')) {
4756             input = InpD;
4757         } else if (c == QLatin1Char('S')) {
4758             input = InpS;
4759         } else if (c == QLatin1Char('P')) {
4760             input = InpS;
4761         } else if (c == QLatin1Char('[')) {
4762             input = InpOB;
4763         } else if (c == QLatin1Char(']')) {
4764             input = InpCB;
4765         } else if (c == QLatin1Char('%')) {
4766             input = InpPer;
4767         } else if (c == QLatin1Char('>')) {
4768             input = InpGt;
4769         } else {
4770             input = InpUnknown;
4771         }
4772         state = table[state][input];
4773 
4774         switch (state) {
4775             case Doctype:
4776                 parseString_s = QLatin1String("DOCTYPE");
4777                 if (!parseString()) {
4778                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4779                     return false;
4780                 }
4781                 break;
4782             case Ws1:
4783             case Ws2:
4784             case Ws3:
4785             case Ws4:
4786                 if (!eat_ws()) {
4787                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4788                     return false;
4789                 }
4790                 break;
4791             case Doctype2:
4792                 parseName_useRef = false;
4793                 if (!parseName()) {
4794                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4795                     return false;
4796                 }
4797                 break;
4798             case Sys:
4799                 parseExternalID_allowPublicID = false;
4800                 if (!parseExternalID()) {
4801                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4802                     return false;
4803                 }
4804                 thisPublicId = publicId;
4805                 thisSystemId = systemId;
4806                 break;
4807             case MP:
4808             case MPR:
4809                 if (!next_eat_ws()) {
4810                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4811                     return false;
4812                 }
4813                 break;
4814             case PER:
4815                 parsePEReference_context = InDTD;
4816                 if (!parsePEReference()) {
4817                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4818                     return false;
4819                 }
4820                 break;
4821             case Mup:
4822                 if (dtdRecursionLimit > 0 && parameterEntities.size() > dtdRecursionLimit) {
4823                     reportParseError(QString::fromLatin1(
4824                         "DTD parsing exceeded recursion limit of %1.").arg(dtdRecursionLimit));
4825                     return false;
4826                 }
4827                 if (!parseMarkupdecl()) {
4828                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4829                     return false;
4830                 }
4831                 break;
4832             case MPE:
4833                 if (!next_eat_ws()) {
4834                     parseFailed(&QXmlSimpleReaderPrivate::parseDoctype, state);
4835                     return false;
4836                 }
4837                 break;
4838             case Done:
4839                 if (lexicalHnd) {
4840                     if (!startDTDwasReported) {
4841                         startDTDwasReported = true;
4842                         if (!lexicalHnd->startDTD(doctype, publicId, systemId)) {
4843                             reportParseError(lexicalHnd->errorString());
4844                             return false;
4845                         }
4846                     }
4847                     if (!lexicalHnd->endDTD()) {
4848                         reportParseError(lexicalHnd->errorString());
4849                         return false;
4850                     }
4851                 }
4852                 next();
4853                 break;
4854         }
4855     }
4856     return false;
4857 }
4858 
4859 /*
4860   Parse a ExternalID [75].
4861 
4862   If allowPublicID is true parse ExternalID [75] or PublicID [83].
4863 */
parseExternalID()4864 bool QXmlSimpleReaderPrivate::parseExternalID()
4865 {
4866     const signed char Init             =  0;
4867     const signed char Sys              =  1; // parse 'SYSTEM'
4868     const signed char SysWS            =  2; // parse the whitespace after 'SYSTEM'
4869     const signed char SysSQ            =  3; // parse SystemLiteral with '
4870     const signed char SysSQ2           =  4; // parse SystemLiteral with '
4871     const signed char SysDQ            =  5; // parse SystemLiteral with "
4872     const signed char SysDQ2           =  6; // parse SystemLiteral with "
4873     const signed char Pub              =  7; // parse 'PUBLIC'
4874     const signed char PubWS            =  8; // parse the whitespace after 'PUBLIC'
4875     const signed char PubSQ            =  9; // parse PubidLiteral with '
4876     const signed char PubSQ2           = 10; // parse PubidLiteral with '
4877     const signed char PubDQ            = 11; // parse PubidLiteral with "
4878     const signed char PubDQ2           = 12; // parse PubidLiteral with "
4879     const signed char PubE             = 13; // finished parsing the PubidLiteral
4880     const signed char PubWS2           = 14; // parse the whitespace after the PubidLiteral
4881     const signed char PDone            = 15; // done if allowPublicID is true
4882     const signed char Done             = 16;
4883 
4884     const signed char InpSQ            = 0; // '
4885     const signed char InpDQ            = 1; // "
4886     const signed char InpS             = 2; // S
4887     const signed char InpP             = 3; // P
4888     const signed char InpWs            = 4; // white space
4889     const signed char InpUnknown       = 5;
4890 
4891     static const signed char table[15][6] = {
4892      /*  InpSQ    InpDQ    InpS     InpP     InpWs     InpUnknown */
4893         { -1,      -1,      Sys,     Pub,     -1,       -1      }, // Init
4894         { -1,      -1,      -1,      -1,      SysWS,    -1      }, // Sys
4895         { SysSQ,   SysDQ,   -1,      -1,      -1,       -1      }, // SysWS
4896         { Done,    SysSQ2,  SysSQ2,  SysSQ2,  SysSQ2,   SysSQ2  }, // SysSQ
4897         { Done,    SysSQ2,  SysSQ2,  SysSQ2,  SysSQ2,   SysSQ2  }, // SysSQ2
4898         { SysDQ2,  Done,    SysDQ2,  SysDQ2,  SysDQ2,   SysDQ2  }, // SysDQ
4899         { SysDQ2,  Done,    SysDQ2,  SysDQ2,  SysDQ2,   SysDQ2  }, // SysDQ2
4900         { -1,      -1,      -1,      -1,      PubWS,    -1      }, // Pub
4901         { PubSQ,   PubDQ,   -1,      -1,      -1,       -1      }, // PubWS
4902         { PubE,    -1,      PubSQ2,  PubSQ2,  PubSQ2,   PubSQ2  }, // PubSQ
4903         { PubE,    -1,      PubSQ2,  PubSQ2,  PubSQ2,   PubSQ2  }, // PubSQ2
4904         { -1,      PubE,    PubDQ2,  PubDQ2,  PubDQ2,   PubDQ2  }, // PubDQ
4905         { -1,      PubE,    PubDQ2,  PubDQ2,  PubDQ2,   PubDQ2  }, // PubDQ2
4906         { PDone,   PDone,   PDone,   PDone,   PubWS2,   PDone   }, // PubE
4907         { SysSQ,   SysDQ,   PDone,   PDone,   PDone,    PDone   }  // PubWS2
4908     };
4909     signed char state;
4910     signed char input;
4911 
4912     if (parseStack == nullptr || parseStack->isEmpty()) {
4913         systemId.clear();
4914         publicId.clear();
4915         state = Init;
4916     } else {
4917         state = parseStack->pop().state;
4918 #if defined(QT_QXML_DEBUG)
4919         qDebug("QXmlSimpleReader: parseExternalID (cont) in state %d", state);
4920 #endif
4921         if (!parseStack->isEmpty()) {
4922             ParseFunction function = parseStack->top().function;
4923             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
4924                 parseStack->pop();
4925 #if defined(QT_QXML_DEBUG)
4926                 qDebug("QXmlSimpleReader: eat_ws (cont)");
4927 #endif
4928             }
4929             if (!(this->*function)()) {
4930                 parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
4931                 return false;
4932             }
4933         }
4934     }
4935 
4936     for (;;) {
4937         switch (state) {
4938             case PDone:
4939                 if (parseExternalID_allowPublicID) {
4940                     publicId = string();
4941                     return true;
4942                 } else {
4943                     reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
4944                     return false;
4945                 }
4946             case Done:
4947                 return true;
4948             case -1:
4949                 // Error
4950                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
4951                 return false;
4952         }
4953 
4954         if (atEnd()) {
4955             unexpectedEof(&QXmlSimpleReaderPrivate::parseExternalID, state);
4956             return false;
4957         }
4958         if (is_S(c)) {
4959             input = InpWs;
4960         } else if (c == QLatin1Char('\'')) {
4961             input = InpSQ;
4962         } else if (c == QLatin1Char('"')) {
4963             input = InpDQ;
4964         } else if (c == QLatin1Char('S')) {
4965             input = InpS;
4966         } else if (c == QLatin1Char('P')) {
4967             input = InpP;
4968         } else {
4969             input = InpUnknown;
4970         }
4971         state = table[state][input];
4972 
4973         switch (state) {
4974             case Sys:
4975                 parseString_s = QLatin1String("SYSTEM");
4976                 if (!parseString()) {
4977                     parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
4978                     return false;
4979                 }
4980                 break;
4981             case SysWS:
4982                 if (!eat_ws()) {
4983                     parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
4984                     return false;
4985                 }
4986                 break;
4987             case SysSQ:
4988             case SysDQ:
4989                 stringClear();
4990                 next();
4991                 break;
4992             case SysSQ2:
4993             case SysDQ2:
4994                 stringAddC();
4995                 next();
4996                 break;
4997             case Pub:
4998                 parseString_s = QLatin1String("PUBLIC");
4999                 if (!parseString()) {
5000                     parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
5001                     return false;
5002                 }
5003                 break;
5004             case PubWS:
5005                 if (!eat_ws()) {
5006                     parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
5007                     return false;
5008                 }
5009                 break;
5010             case PubSQ:
5011             case PubDQ:
5012                 stringClear();
5013                 next();
5014                 break;
5015             case PubSQ2:
5016             case PubDQ2:
5017                 stringAddC();
5018                 next();
5019                 break;
5020             case PubE:
5021                 next();
5022                 break;
5023             case PubWS2:
5024                 publicId = string();
5025                 if (!eat_ws()) {
5026                     parseFailed(&QXmlSimpleReaderPrivate::parseExternalID, state);
5027                     return false;
5028                 }
5029                 break;
5030             case Done:
5031                 systemId = string();
5032                 next();
5033                 break;
5034         }
5035     }
5036     return false;
5037 }
5038 
5039 /*
5040   Parse a markupdecl [29].
5041 */
parseMarkupdecl()5042 bool QXmlSimpleReaderPrivate::parseMarkupdecl()
5043 {
5044     const signed char Init             = 0;
5045     const signed char Lt               = 1; // < was read
5046     const signed char Em               = 2; // ! was read
5047     const signed char CE               = 3; // E was read
5048     const signed char Qm               = 4; // ? was read
5049     const signed char Dash             = 5; // - was read
5050     const signed char CA               = 6; // A was read
5051     const signed char CEL              = 7; // EL was read
5052     const signed char CEN              = 8; // EN was read
5053     const signed char CN               = 9; // N was read
5054     const signed char Done             = 10;
5055 
5056     const signed char InpLt            = 0; // <
5057     const signed char InpQm            = 1; // ?
5058     const signed char InpEm            = 2; // !
5059     const signed char InpDash          = 3; // -
5060     const signed char InpA             = 4; // A
5061     const signed char InpE             = 5; // E
5062     const signed char InpL             = 6; // L
5063     const signed char InpN             = 7; // N
5064     const signed char InpUnknown       = 8;
5065 
5066     static const signed char table[4][9] = {
5067      /*  InpLt  InpQm  InpEm  InpDash  InpA   InpE   InpL   InpN   InpUnknown */
5068         { Lt,    -1,    -1,    -1,      -1,    -1,    -1,    -1,    -1     }, // Init
5069         { -1,    Qm,    Em,    -1,      -1,    -1,    -1,    -1,    -1     }, // Lt
5070         { -1,    -1,    -1,    Dash,    CA,    CE,    -1,    CN,    -1     }, // Em
5071         { -1,    -1,    -1,    -1,      -1,    -1,    CEL,   CEN,   -1     }  // CE
5072     };
5073     signed char state;
5074     signed char input;
5075 
5076     if (parseStack == nullptr || parseStack->isEmpty()) {
5077         state = Init;
5078     } else {
5079         state = parseStack->pop().state;
5080 #if defined(QT_QXML_DEBUG)
5081         qDebug("QXmlSimpleReader: parseMarkupdecl (cont) in state %d", state);
5082 #endif
5083         if (!parseStack->isEmpty()) {
5084             ParseFunction function = parseStack->top().function;
5085             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
5086                 parseStack->pop();
5087 #if defined(QT_QXML_DEBUG)
5088                 qDebug("QXmlSimpleReader: eat_ws (cont)");
5089 #endif
5090             }
5091             if (!(this->*function)()) {
5092                 parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5093                 return false;
5094             }
5095         }
5096     }
5097 
5098     for (;;) {
5099         switch (state) {
5100             case Qm:
5101                 if (contentHnd) {
5102                     if (!contentHnd->processingInstruction(name(),string())) {
5103                         reportParseError(contentHnd->errorString());
5104                         return false;
5105                     }
5106                 }
5107                 return true;
5108             case Dash:
5109                 if (lexicalHnd) {
5110                     if (!lexicalHnd->comment(string())) {
5111                         reportParseError(lexicalHnd->errorString());
5112                         return false;
5113                     }
5114                 }
5115                 return true;
5116             case CA:
5117                 return true;
5118             case CEL:
5119                 return true;
5120             case CEN:
5121                 return true;
5122             case CN:
5123                 return true;
5124             case Done:
5125                 return true;
5126             case -1:
5127                 // Error
5128                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
5129                 return false;
5130         }
5131 
5132         if (atEnd()) {
5133             unexpectedEof(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5134             return false;
5135         }
5136         if        (c == QLatin1Char('<')) {
5137             input = InpLt;
5138         } else if (c == QLatin1Char('?')) {
5139             input = InpQm;
5140         } else if (c == QLatin1Char('!')) {
5141             input = InpEm;
5142         } else if (c == QLatin1Char('-')) {
5143             input = InpDash;
5144         } else if (c == QLatin1Char('A')) {
5145             input = InpA;
5146         } else if (c == QLatin1Char('E')) {
5147             input = InpE;
5148         } else if (c == QLatin1Char('L')) {
5149             input = InpL;
5150         } else if (c == QLatin1Char('N')) {
5151             input = InpN;
5152         } else {
5153             input = InpUnknown;
5154         }
5155         state = table[state][input];
5156 
5157         switch (state) {
5158             case Lt:
5159                 next();
5160                 break;
5161             case Em:
5162                 next();
5163                 break;
5164             case CE:
5165                 next();
5166                 break;
5167             case Qm:
5168                 parsePI_xmldecl = false;
5169                 if (!parsePI()) {
5170                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5171                     return false;
5172                 }
5173                 break;
5174             case Dash:
5175                 if (!parseComment()) {
5176                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5177                     return false;
5178                 }
5179                 break;
5180             case CA:
5181                 if (!parseAttlistDecl()) {
5182                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5183                     return false;
5184                 }
5185                 break;
5186             case CEL:
5187                 if (!parseElementDecl()) {
5188                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5189                     return false;
5190                 }
5191                 break;
5192             case CEN:
5193                 if (!parseEntityDecl()) {
5194                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5195                     return false;
5196                 }
5197                 break;
5198             case CN:
5199                 if (!parseNotationDecl()) {
5200                     parseFailed(&QXmlSimpleReaderPrivate::parseMarkupdecl, state);
5201                     return false;
5202                 }
5203                 break;
5204         }
5205     }
5206     return false;
5207 }
5208 
5209 /*
5210   Parse a PEReference [69]
5211 */
parsePEReference()5212 bool QXmlSimpleReaderPrivate::parsePEReference()
5213 {
5214     const signed char Init             = 0;
5215     const signed char Next             = 1;
5216     const signed char Name             = 2;
5217     const signed char NameR            = 3; // same as Name, but already reported
5218     const signed char Done             = 4;
5219 
5220     const signed char InpSemi          = 0; // ;
5221     const signed char InpPer           = 1; // %
5222     const signed char InpUnknown       = 2;
5223 
5224     static const signed char table[4][3] = {
5225      /*  InpSemi  InpPer  InpUnknown */
5226         { -1,      Next,   -1    }, // Init
5227         { -1,      -1,     Name  }, // Next
5228         { Done,    -1,     -1    }, // Name
5229         { Done,    -1,     -1    }  // NameR
5230     };
5231     signed char state;
5232     signed char input;
5233 
5234     if (parseStack == nullptr || parseStack->isEmpty()) {
5235         state = Init;
5236     } else {
5237         state = parseStack->pop().state;
5238 #if defined(QT_QXML_DEBUG)
5239         qDebug("QXmlSimpleReader: parsePEReference (cont) in state %d", state);
5240 #endif
5241         if (!parseStack->isEmpty()) {
5242             ParseFunction function = parseStack->top().function;
5243             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
5244                 parseStack->pop();
5245 #if defined(QT_QXML_DEBUG)
5246                 qDebug("QXmlSimpleReader: eat_ws (cont)");
5247 #endif
5248             }
5249             if (!(this->*function)()) {
5250                 parseFailed(&QXmlSimpleReaderPrivate::parsePEReference, state);
5251                 return false;
5252             }
5253         }
5254     }
5255 
5256     for (;;) {
5257         switch (state) {
5258             case Name:
5259                 {
5260                     bool skipIt = true;
5261                     QString xmlRefString;
5262 
5263                     QMap<QString,QString>::Iterator it;
5264                     it = parameterEntities.find(ref());
5265                     if (it != parameterEntities.end()) {
5266                         skipIt = false;
5267                         xmlRefString = *it;
5268                     } else if (entityRes) {
5269                         QMap<QString,QXmlSimpleReaderPrivate::ExternParameterEntity>::Iterator it2;
5270                         it2 = externParameterEntities.find(ref());
5271 QT_WARNING_PUSH
5272 QT_WARNING_DISABLE_DEPRECATED
5273                         QXmlInputSource *ret = nullptr;
5274 QT_WARNING_POP
5275                         if (it2 != externParameterEntities.end()) {
5276                             if (!entityRes->resolveEntity((*it2).publicId, (*it2).systemId, ret)) {
5277                                 delete ret;
5278                                 reportParseError(entityRes->errorString());
5279                                 return false;
5280                             }
5281                             if (ret) {
5282                                 QString buffer = ret->data();
5283                                 while (!buffer.isEmpty()) {
5284                                     xmlRefString += buffer;
5285                                     ret->fetchData();
5286                                     buffer = ret->data();
5287                                 }
5288                                 delete ret;
5289                                 if (!stripTextDecl(xmlRefString)) {
5290                                     reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL));
5291                                     return false;
5292                                 }
5293                                 skipIt = false;
5294                             }
5295                         }
5296                     }
5297 
5298                     if (skipIt) {
5299                         if (contentHnd) {
5300                             if (!contentHnd->skippedEntity(QLatin1Char('%') + ref())) {
5301                                 reportParseError(contentHnd->errorString());
5302                                 return false;
5303                             }
5304                         }
5305                     } else {
5306                         if (parsePEReference_context == InEntityValue) {
5307                             // Included in literal
5308                             if (!insertXmlRef(xmlRefString, ref(), true))
5309                                 return false;
5310                         } else if (parsePEReference_context == InDTD) {
5311                             // Included as PE
5312                             if (!insertXmlRef(QLatin1Char(' ') + xmlRefString + QLatin1Char(' '), ref(), false))
5313                                 return false;
5314                         }
5315                     }
5316                 }
5317                 state = NameR;
5318                 break;
5319             case Done:
5320                 return true;
5321             case -1:
5322                 // Error
5323                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
5324                 return false;
5325         }
5326 
5327         if (atEnd()) {
5328             unexpectedEof(&QXmlSimpleReaderPrivate::parsePEReference, state);
5329             return false;
5330         }
5331         if        (c == QLatin1Char(';')) {
5332             input = InpSemi;
5333         } else if (c == QLatin1Char('%')) {
5334             input = InpPer;
5335         } else {
5336             input = InpUnknown;
5337         }
5338         state = table[state][input];
5339 
5340         switch (state) {
5341             case Next:
5342                 next();
5343                 break;
5344             case Name:
5345             case NameR:
5346                 parseName_useRef = true;
5347                 if (!parseName()) {
5348                     parseFailed(&QXmlSimpleReaderPrivate::parsePEReference, state);
5349                     return false;
5350                 }
5351                 break;
5352             case Done:
5353                 next();
5354                 break;
5355         }
5356     }
5357     return false;
5358 }
5359 
5360 /*
5361   Parse a AttlistDecl [52].
5362 
5363   Precondition: the beginning '<!' is already read and the head
5364   stands on the 'A' of '<!ATTLIST'
5365 */
parseAttlistDecl()5366 bool QXmlSimpleReaderPrivate::parseAttlistDecl()
5367 {
5368     const signed char Init             =  0;
5369     const signed char Attlist          =  1; // parse the string "ATTLIST"
5370     const signed char Ws               =  2; // whitespace read
5371     const signed char Name             =  3; // parse name
5372     const signed char Ws1              =  4; // whitespace read
5373     const signed char Attdef           =  5; // parse the AttDef
5374     const signed char Ws2              =  6; // whitespace read
5375     const signed char Atttype          =  7; // parse the AttType
5376     const signed char Ws3              =  8; // whitespace read
5377     const signed char DDecH            =  9; // DefaultDecl with #
5378     const signed char DefReq           = 10; // parse the string "REQUIRED"
5379     const signed char DefImp           = 11; // parse the string "IMPLIED"
5380     const signed char DefFix           = 12; // parse the string "FIXED"
5381     const signed char Attval           = 13; // parse the AttValue
5382     const signed char Ws4              = 14; // whitespace read
5383     const signed char Done             = 15;
5384 
5385     const signed char InpWs            = 0; // white space
5386     const signed char InpGt            = 1; // >
5387     const signed char InpHash          = 2; // #
5388     const signed char InpA             = 3; // A
5389     const signed char InpI             = 4; // I
5390     const signed char InpF             = 5; // F
5391     const signed char InpR             = 6; // R
5392     const signed char InpUnknown       = 7;
5393 
5394     static const signed char table[15][8] = {
5395      /*  InpWs    InpGt    InpHash  InpA      InpI     InpF     InpR     InpUnknown */
5396         { -1,      -1,      -1,      Attlist,  -1,      -1,      -1,      -1      }, // Init
5397         { Ws,      -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attlist
5398         { -1,      -1,      -1,      Name,     Name,    Name,    Name,    Name    }, // Ws
5399         { Ws1,     Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }, // Name
5400         { -1,      Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }, // Ws1
5401         { Ws2,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attdef
5402         { -1,      Atttype, Atttype, Atttype,  Atttype, Atttype, Atttype, Atttype }, // Ws2
5403         { Ws3,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // Attype
5404         { -1,      Attval,  DDecH,   Attval,   Attval,  Attval,  Attval,  Attval  }, // Ws3
5405         { -1,      -1,      -1,      -1,       DefImp,  DefFix,  DefReq,  -1      }, // DDecH
5406         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // DefReq
5407         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // DefImp
5408         { Ws3,     -1,      -1,      -1,       -1,      -1,      -1,      -1      }, // DefFix
5409         { Ws4,     Ws4,     -1,      -1,       -1,      -1,      -1,      -1      }, // Attval
5410         { -1,      Done,    Attdef,  Attdef,   Attdef,  Attdef,  Attdef,  Attdef  }  // Ws4
5411     };
5412     signed char state;
5413     signed char input;
5414 
5415     if (parseStack == nullptr || parseStack->isEmpty()) {
5416         state = Init;
5417     } else {
5418         state = parseStack->pop().state;
5419 #if defined(QT_QXML_DEBUG)
5420         qDebug("QXmlSimpleReader: parseAttlistDecl (cont) in state %d", state);
5421 #endif
5422         if (!parseStack->isEmpty()) {
5423             ParseFunction function = parseStack->top().function;
5424             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
5425                 parseStack->pop();
5426 #if defined(QT_QXML_DEBUG)
5427                 qDebug("QXmlSimpleReader: eat_ws (cont)");
5428 #endif
5429             }
5430             if (!(this->*function)()) {
5431                 parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5432                 return false;
5433             }
5434         }
5435     }
5436 
5437     for (;;) {
5438         switch (state) {
5439             case Name:
5440                 attDeclEName = name();
5441                 break;
5442             case Attdef:
5443                 attDeclAName = name();
5444                 break;
5445             case Done:
5446                 return true;
5447             case -1:
5448                 // Error
5449                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
5450                 return false;
5451         }
5452 
5453         if (atEnd()) {
5454             unexpectedEof(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5455             return false;
5456         }
5457         if (is_S(c)) {
5458             input = InpWs;
5459         } else if (c == QLatin1Char('>')) {
5460             input = InpGt;
5461         } else if (c == QLatin1Char('#')) {
5462             input = InpHash;
5463         } else if (c == QLatin1Char('A')) {
5464             input = InpA;
5465         } else if (c == QLatin1Char('I')) {
5466             input = InpI;
5467         } else if (c == QLatin1Char('F')) {
5468             input = InpF;
5469         } else if (c == QLatin1Char('R')) {
5470             input = InpR;
5471         } else {
5472             input = InpUnknown;
5473         }
5474         state = table[state][input];
5475 
5476         switch (state) {
5477             case Attlist:
5478                 parseString_s = QLatin1String("ATTLIST");
5479                 if (!parseString()) {
5480                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5481                     return false;
5482                 }
5483                 break;
5484             case Ws:
5485             case Ws1:
5486             case Ws2:
5487             case Ws3:
5488                 if (!eat_ws()) {
5489                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5490                     return false;
5491                 }
5492                 break;
5493             case Name:
5494                 parseName_useRef = false;
5495                 if (!parseName()) {
5496                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5497                     return false;
5498                 }
5499                 break;
5500             case Attdef:
5501                 parseName_useRef = false;
5502                 if (!parseName()) {
5503                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5504                     return false;
5505                 }
5506                 break;
5507             case Atttype:
5508                 if (!parseAttType()) {
5509                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5510                     return false;
5511                 }
5512                 break;
5513             case DDecH:
5514                 next();
5515                 break;
5516             case DefReq:
5517                 parseString_s = QLatin1String("REQUIRED");
5518                 if (!parseString()) {
5519                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5520                     return false;
5521                 }
5522                 break;
5523             case DefImp:
5524                 parseString_s = QLatin1String("IMPLIED");
5525                 if (!parseString()) {
5526                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5527                     return false;
5528                 }
5529                 break;
5530             case DefFix:
5531                 parseString_s = QLatin1String("FIXED");
5532                 if (!parseString()) {
5533                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5534                     return false;
5535                 }
5536                 break;
5537             case Attval:
5538                 if (!parseAttValue()) {
5539                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5540                     return false;
5541                 }
5542                 break;
5543             case Ws4:
5544                 if (declHnd) {
5545                     // ### not all values are computed yet...
5546                     if (!declHnd->attributeDecl(attDeclEName, attDeclAName, QLatin1String(""), QLatin1String(""), QLatin1String(""))) {
5547                         reportParseError(declHnd->errorString());
5548                         return false;
5549                     }
5550                 }
5551                 if (!eat_ws()) {
5552                     parseFailed(&QXmlSimpleReaderPrivate::parseAttlistDecl, state);
5553                     return false;
5554                 }
5555                 break;
5556             case Done:
5557                 next();
5558                 break;
5559         }
5560     }
5561     return false;
5562 }
5563 
5564 /*
5565   Parse a AttType [54]
5566 */
parseAttType()5567 bool QXmlSimpleReaderPrivate::parseAttType()
5568 {
5569     const signed char Init             =  0;
5570     const signed char ST               =  1; // StringType
5571     const signed char TTI              =  2; // TokenizedType starting with 'I'
5572     const signed char TTI2             =  3; // TokenizedType helpstate
5573     const signed char TTI3             =  4; // TokenizedType helpstate
5574     const signed char TTE              =  5; // TokenizedType starting with 'E'
5575     const signed char TTEY             =  6; // TokenizedType starting with 'ENTITY'
5576     const signed char TTEI             =  7; // TokenizedType starting with 'ENTITI'
5577     const signed char N                =  8; // N read (TokenizedType or Notation)
5578     const signed char TTNM             =  9; // TokenizedType starting with 'NM'
5579     const signed char TTNM2            = 10; // TokenizedType helpstate
5580     const signed char NO               = 11; // Notation
5581     const signed char NO2              = 12; // Notation helpstate
5582     const signed char NO3              = 13; // Notation helpstate
5583     const signed char NOName           = 14; // Notation, read name
5584     const signed char NO4              = 15; // Notation helpstate
5585     const signed char EN               = 16; // Enumeration
5586     const signed char ENNmt            = 17; // Enumeration, read Nmtoken
5587     const signed char EN2              = 18; // Enumeration helpstate
5588     const signed char ADone            = 19; // almost done (make next and accept)
5589     const signed char Done             = 20;
5590 
5591     const signed char InpWs            =  0; // whitespace
5592     const signed char InpOp            =  1; // (
5593     const signed char InpCp            =  2; //)
5594     const signed char InpPipe          =  3; // |
5595     const signed char InpC             =  4; // C
5596     const signed char InpE             =  5; // E
5597     const signed char InpI             =  6; // I
5598     const signed char InpM             =  7; // M
5599     const signed char InpN             =  8; // N
5600     const signed char InpO             =  9; // O
5601     const signed char InpR             = 10; // R
5602     const signed char InpS             = 11; // S
5603     const signed char InpY             = 12; // Y
5604     const signed char InpUnknown       = 13;
5605 
5606     static const signed char table[19][14] = {
5607      /*  InpWs    InpOp    InpCp    InpPipe  InpC     InpE     InpI     InpM     InpN     InpO     InpR     InpS     InpY     InpUnknown */
5608         { -1,      EN,      -1,      -1,      ST,      TTE,     TTI,     -1,      N,       -1,      -1,      -1,      -1,      -1     }, // Init
5609         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // ST
5610         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTI2,    Done,    Done,    Done   }, // TTI
5611         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTI3,    Done,    Done   }, // TTI2
5612         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTI3
5613         { -1,      -1,      -1,      -1,      -1,      -1,      TTEI,    -1,      -1,      -1,      -1,      -1,      TTEY,    -1     }, // TTE
5614         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTEY
5615         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTEI
5616         { -1,      -1,      -1,      -1,      -1,      -1,      -1,      TTNM,    -1,      NO,      -1,      -1,      -1,      -1     }, // N
5617         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    TTNM2,   Done,    Done   }, // TTNM
5618         { Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done,    Done   }, // TTNM2
5619         { NO2,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO
5620         { -1,      NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO2
5621         { NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName,  NOName }, // NO3
5622         { NO4,     -1,      ADone,   NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NOName
5623         { -1,      -1,      ADone,   NO3,     -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // NO4
5624         { -1,      -1,      ENNmt,   -1,      ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt,   ENNmt  }, // EN
5625         { EN2,     -1,      ADone,   EN,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }, // ENNmt
5626         { -1,      -1,      ADone,   EN,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1     }  // EN2
5627     };
5628     signed char state;
5629     signed char input;
5630 
5631     if (parseStack == nullptr || parseStack->isEmpty()) {
5632         state = Init;
5633     } else {
5634         state = parseStack->pop().state;
5635 #if defined(QT_QXML_DEBUG)
5636         qDebug("QXmlSimpleReader: parseAttType (cont) in state %d", state);
5637 #endif
5638         if (!parseStack->isEmpty()) {
5639             ParseFunction function = parseStack->top().function;
5640             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
5641                 parseStack->pop();
5642 #if defined(QT_QXML_DEBUG)
5643                 qDebug("QXmlSimpleReader: eat_ws (cont)");
5644 #endif
5645             }
5646             if (!(this->*function)()) {
5647                 parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5648                 return false;
5649             }
5650         }
5651     }
5652 
5653     for (;;) {
5654         switch (state) {
5655             case ADone:
5656                 return true;
5657             case Done:
5658                 return true;
5659             case -1:
5660                 // Error
5661                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
5662                 return false;
5663         }
5664 
5665         if (atEnd()) {
5666             unexpectedEof(&QXmlSimpleReaderPrivate::parseAttType, state);
5667             return false;
5668         }
5669         if (is_S(c)) {
5670             input = InpWs;
5671         } else if (c == QLatin1Char('(')) {
5672             input = InpOp;
5673         } else if (c == QLatin1Char(')')) {
5674             input = InpCp;
5675         } else if (c == QLatin1Char('|')) {
5676             input = InpPipe;
5677         } else if (c == QLatin1Char('C')) {
5678             input = InpC;
5679         } else if (c == QLatin1Char('E')) {
5680             input = InpE;
5681         } else if (c == QLatin1Char('I')) {
5682             input = InpI;
5683         } else if (c == QLatin1Char('M')) {
5684             input = InpM;
5685         } else if (c == QLatin1Char('N')) {
5686             input = InpN;
5687         } else if (c == QLatin1Char('O')) {
5688             input = InpO;
5689         } else if (c == QLatin1Char('R')) {
5690             input = InpR;
5691         } else if (c == QLatin1Char('S')) {
5692             input = InpS;
5693         } else if (c == QLatin1Char('Y')) {
5694             input = InpY;
5695         } else {
5696             input = InpUnknown;
5697         }
5698         state = table[state][input];
5699 
5700         switch (state) {
5701             case ST:
5702                 parseString_s = QLatin1String("CDATA");
5703                 if (!parseString()) {
5704                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5705                     return false;
5706                 }
5707                 break;
5708             case TTI:
5709                 parseString_s = QLatin1String("ID");
5710                 if (!parseString()) {
5711                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5712                     return false;
5713                 }
5714                 break;
5715             case TTI2:
5716                 parseString_s = QLatin1String("REF");
5717                 if (!parseString()) {
5718                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5719                     return false;
5720                 }
5721                 break;
5722             case TTI3:
5723                 next(); // S
5724                 break;
5725             case TTE:
5726                 parseString_s = QLatin1String("ENTIT");
5727                 if (!parseString()) {
5728                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5729                     return false;
5730                 }
5731                 break;
5732             case TTEY:
5733                 next(); // Y
5734                 break;
5735             case TTEI:
5736                 parseString_s = QLatin1String("IES");
5737                 if (!parseString()) {
5738                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5739                     return false;
5740                 }
5741                 break;
5742             case N:
5743                 next(); // N
5744                 break;
5745             case TTNM:
5746                 parseString_s = QLatin1String("MTOKEN");
5747                 if (!parseString()) {
5748                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5749                     return false;
5750                 }
5751                 break;
5752             case TTNM2:
5753                 next(); // S
5754                 break;
5755             case NO:
5756                 parseString_s = QLatin1String("OTATION");
5757                 if (!parseString()) {
5758                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5759                     return false;
5760                 }
5761                 break;
5762             case NO2:
5763                 if (!eat_ws()) {
5764                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5765                     return false;
5766                 }
5767                 break;
5768             case NO3:
5769                 if (!next_eat_ws()) {
5770                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5771                     return false;
5772                 }
5773                 break;
5774             case NOName:
5775                 parseName_useRef = false;
5776                 if (!parseName()) {
5777                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5778                     return false;
5779                 }
5780                 break;
5781             case NO4:
5782                 if (!eat_ws()) {
5783                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5784                     return false;
5785                 }
5786                 break;
5787             case EN:
5788                 if (!next_eat_ws()) {
5789                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5790                     return false;
5791                 }
5792                 break;
5793             case ENNmt:
5794                 if (!parseNmtoken()) {
5795                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5796                     return false;
5797                 }
5798                 break;
5799             case EN2:
5800                 if (!eat_ws()) {
5801                     parseFailed(&QXmlSimpleReaderPrivate::parseAttType, state);
5802                     return false;
5803                 }
5804                 break;
5805             case ADone:
5806                 next();
5807                 break;
5808         }
5809     }
5810     return false;
5811 }
5812 
5813 /*
5814   Parse a AttValue [10]
5815 
5816   Precondition: the head stands on the beginning " or '
5817 
5818   If this function was successful, the head stands on the first
5819   character after the closing " or ' and the value of the attribute
5820   is in string().
5821 */
parseAttValue()5822 bool QXmlSimpleReaderPrivate::parseAttValue()
5823 {
5824     const signed char Init             = 0;
5825     const signed char Dq               = 1; // double quotes were read
5826     const signed char DqRef            = 2; // read references in double quotes
5827     const signed char DqC              = 3; // signed character read in double quotes
5828     const signed char Sq               = 4; // single quotes were read
5829     const signed char SqRef            = 5; // read references in single quotes
5830     const signed char SqC              = 6; // signed character read in single quotes
5831     const signed char Done             = 7;
5832 
5833     const signed char InpDq            = 0; // "
5834     const signed char InpSq            = 1; // '
5835     const signed char InpAmp           = 2; // &
5836     const signed char InpLt            = 3; // <
5837     const signed char InpUnknown       = 4;
5838 
5839     static const signed char table[7][5] = {
5840      /*  InpDq  InpSq  InpAmp  InpLt InpUnknown */
5841         { Dq,    Sq,    -1,     -1,   -1    }, // Init
5842         { Done,  DqC,   DqRef,  -1,   DqC   }, // Dq
5843         { Done,  DqC,   DqRef,  -1,   DqC   }, // DqRef
5844         { Done,  DqC,   DqRef,  -1,   DqC   }, // DqC
5845         { SqC,   Done,  SqRef,  -1,   SqC   }, // Sq
5846         { SqC,   Done,  SqRef,  -1,   SqC   }, // SqRef
5847         { SqC,   Done,  SqRef,  -1,   SqC   }  // SqRef
5848     };
5849     signed char state;
5850     signed char input;
5851 
5852     if (parseStack == nullptr || parseStack->isEmpty()) {
5853         state = Init;
5854     } else {
5855         state = parseStack->pop().state;
5856 #if defined(QT_QXML_DEBUG)
5857         qDebug("QXmlSimpleReader: parseAttValue (cont) in state %d", state);
5858 #endif
5859         if (!parseStack->isEmpty()) {
5860             ParseFunction function = parseStack->top().function;
5861             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
5862                 parseStack->pop();
5863 #if defined(QT_QXML_DEBUG)
5864                 qDebug("QXmlSimpleReader: eat_ws (cont)");
5865 #endif
5866             }
5867             if (!(this->*function)()) {
5868                 parseFailed(&QXmlSimpleReaderPrivate::parseAttValue, state);
5869                 return false;
5870             }
5871         }
5872     }
5873 
5874     for (;;) {
5875         switch (state) {
5876             case Done:
5877                 return true;
5878             case -1:
5879                 // Error
5880                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
5881                 return false;
5882         }
5883 
5884         if (atEnd()) {
5885             unexpectedEof(&QXmlSimpleReaderPrivate::parseAttValue, state);
5886             return false;
5887         }
5888         if        (c == QLatin1Char('"')) {
5889             input = InpDq;
5890         } else if (c == QLatin1Char('\'')) {
5891             input = InpSq;
5892         } else if (c == QLatin1Char('&')) {
5893             input = InpAmp;
5894         } else if (c == QLatin1Char('<')) {
5895             input = InpLt;
5896         } else {
5897             input = InpUnknown;
5898         }
5899         state = table[state][input];
5900 
5901         switch (state) {
5902             case Dq:
5903             case Sq:
5904                 stringClear();
5905                 next();
5906                 break;
5907             case DqRef:
5908             case SqRef:
5909                 parseReference_context = InAttributeValue;
5910                 if (!parseReference()) {
5911                     parseFailed(&QXmlSimpleReaderPrivate::parseAttValue, state);
5912                     return false;
5913                 }
5914                 break;
5915             case DqC:
5916             case SqC:
5917                 stringAddC();
5918                 next();
5919                 break;
5920             case Done:
5921                 next();
5922                 break;
5923         }
5924     }
5925     return false;
5926 }
5927 
5928 /*
5929   Parse a elementdecl [45].
5930 
5931   Precondition: the beginning '<!E' is already read and the head
5932   stands on the 'L' of '<!ELEMENT'
5933 */
parseElementDecl()5934 bool QXmlSimpleReaderPrivate::parseElementDecl()
5935 {
5936     const signed char Init             =  0;
5937     const signed char Elem             =  1; // parse the beginning string
5938     const signed char Ws1              =  2; // whitespace required
5939     const signed char Nam              =  3; // parse Name
5940     const signed char Ws2              =  4; // whitespace required
5941     const signed char Empty            =  5; // read EMPTY
5942     const signed char Any              =  6; // read ANY
5943     const signed char Cont             =  7; // read contentspec (except ANY or EMPTY)
5944     const signed char Mix              =  8; // read Mixed
5945     const signed char Mix2             =  9; //
5946     const signed char Mix3             = 10; //
5947     const signed char MixN1            = 11; //
5948     const signed char MixN2            = 12; //
5949     const signed char MixN3            = 13; //
5950     const signed char MixN4            = 14; //
5951     const signed char Cp               = 15; // parse cp
5952     const signed char Cp2              = 16; //
5953     const signed char WsD              = 17; // eat whitespace before Done
5954     const signed char Done             = 18;
5955 
5956     const signed char InpWs            =  0;
5957     const signed char InpGt            =  1; // >
5958     const signed char InpPipe          =  2; // |
5959     const signed char InpOp            =  3; // (
5960     const signed char InpCp            =  4; //)
5961     const signed char InpHash          =  5; // #
5962     const signed char InpQm            =  6; // ?
5963     const signed char InpAst           =  7; // *
5964     const signed char InpPlus          =  8; // +
5965     const signed char InpA             =  9; // A
5966     const signed char InpE             = 10; // E
5967     const signed char InpL             = 11; // L
5968     const signed char InpUnknown       = 12;
5969 
5970     static const signed char table[18][13] = {
5971      /*  InpWs   InpGt  InpPipe  InpOp  InpCp   InpHash  InpQm  InpAst  InpPlus  InpA    InpE    InpL    InpUnknown */
5972         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     Elem,   -1     }, // Init
5973         { Ws1,    -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Elem
5974         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      Nam,    Nam,    Nam,    Nam    }, // Ws1
5975         { Ws2,    -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Nam
5976         { -1,     -1,    -1,      Cont,  -1,     -1,      -1,    -1,     -1,      Any,    Empty,  -1,     -1     }, // Ws2
5977         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Empty
5978         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Any
5979         { -1,     -1,    -1,      Cp,    Cp,     Mix,     -1,    -1,     -1,      Cp,     Cp,     Cp,     Cp     }, // Cont
5980         { Mix2,   -1,    MixN1,   -1,    Mix3,   -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Mix
5981         { -1,     -1,    MixN1,   -1,    Mix3,   -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Mix2
5982         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    WsD,    -1,      -1,     -1,     -1,     -1     }, // Mix3
5983         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    -1,     -1,      MixN2,  MixN2,  MixN2,  MixN2  }, // MixN1
5984         { MixN3,  -1,    MixN1,   -1,    MixN4,  -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // MixN2
5985         { -1,     -1,    MixN1,   -1,    MixN4,  -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // MixN3
5986         { -1,     -1,    -1,      -1,    -1,     -1,      -1,    WsD,    -1,      -1,     -1,     -1,     -1     }, // MixN4
5987         { WsD,    Done,  -1,      -1,    -1,     -1,      Cp2,   Cp2,    Cp2,     -1,     -1,     -1,     -1     }, // Cp
5988         { WsD,    Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }, // Cp2
5989         { -1,     Done,  -1,      -1,    -1,     -1,      -1,    -1,     -1,      -1,     -1,     -1,     -1     }  // WsD
5990     };
5991     signed char state;
5992     signed char input;
5993 
5994     if (parseStack == nullptr || parseStack->isEmpty()) {
5995         state = Init;
5996     } else {
5997         state = parseStack->pop().state;
5998 #if defined(QT_QXML_DEBUG)
5999         qDebug("QXmlSimpleReader: parseElementDecl (cont) in state %d", state);
6000 #endif
6001         if (!parseStack->isEmpty()) {
6002             ParseFunction function = parseStack->top().function;
6003             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6004                 parseStack->pop();
6005 #if defined(QT_QXML_DEBUG)
6006                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6007 #endif
6008             }
6009             if (!(this->*function)()) {
6010                 parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6011                 return false;
6012             }
6013         }
6014     }
6015 
6016     for (;;) {
6017         switch (state) {
6018             case Done:
6019                 return true;
6020             case -1:
6021                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
6022                 return false;
6023         }
6024 
6025         if (atEnd()) {
6026             unexpectedEof(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6027             return false;
6028         }
6029         if (is_S(c)) {
6030             input = InpWs;
6031         } else if (c == QLatin1Char('>')) {
6032             input = InpGt;
6033         } else if (c == QLatin1Char('|')) {
6034             input = InpPipe;
6035         } else if (c == QLatin1Char('(')) {
6036             input = InpOp;
6037         } else if (c == QLatin1Char(')')) {
6038             input = InpCp;
6039         } else if (c == QLatin1Char('#')) {
6040             input = InpHash;
6041         } else if (c == QLatin1Char('?')) {
6042             input = InpQm;
6043         } else if (c == QLatin1Char('*')) {
6044             input = InpAst;
6045         } else if (c == QLatin1Char('+')) {
6046             input = InpPlus;
6047         } else if (c == QLatin1Char('A')) {
6048             input = InpA;
6049         } else if (c == QLatin1Char('E')) {
6050             input = InpE;
6051         } else if (c == QLatin1Char('L')) {
6052             input = InpL;
6053         } else {
6054             input = InpUnknown;
6055         }
6056         state = table[state][input];
6057 
6058         switch (state) {
6059             case Elem:
6060                 parseString_s = QLatin1String("LEMENT");
6061                 if (!parseString()) {
6062                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6063                     return false;
6064                 }
6065                 break;
6066             case Ws1:
6067                 if (!eat_ws()) {
6068                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6069                     return false;
6070                 }
6071                 break;
6072             case Nam:
6073                 parseName_useRef = false;
6074                 if (!parseName()) {
6075                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6076                     return false;
6077                 }
6078                 break;
6079             case Ws2:
6080                 if (!eat_ws()) {
6081                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6082                     return false;
6083                 }
6084                 break;
6085             case Empty:
6086                 parseString_s = QLatin1String("EMPTY");
6087                 if (!parseString()) {
6088                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6089                     return false;
6090                 }
6091                 break;
6092             case Any:
6093                 parseString_s = QLatin1String("ANY");
6094                 if (!parseString()) {
6095                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6096                     return false;
6097                 }
6098                 break;
6099             case Cont:
6100                 if (!next_eat_ws()) {
6101                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6102                     return false;
6103                 }
6104                 break;
6105             case Mix:
6106                 parseString_s = QLatin1String("#PCDATA");
6107                 if (!parseString()) {
6108                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6109                     return false;
6110                 }
6111                 break;
6112             case Mix2:
6113                 if (!eat_ws()) {
6114                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6115                     return false;
6116                 }
6117                 break;
6118             case Mix3:
6119                 next();
6120                 break;
6121             case MixN1:
6122                 if (!next_eat_ws()) {
6123                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6124                     return false;
6125                 }
6126                 break;
6127             case MixN2:
6128                 parseName_useRef = false;
6129                 if (!parseName()) {
6130                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6131                     return false;
6132                 }
6133                 break;
6134             case MixN3:
6135                 if (!eat_ws()) {
6136                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6137                     return false;
6138                 }
6139                 break;
6140             case MixN4:
6141                 next();
6142                 break;
6143             case Cp:
6144                 if (!parseChoiceSeq()) {
6145                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6146                     return false;
6147                 }
6148                 break;
6149             case Cp2:
6150                 next();
6151                 break;
6152             case WsD:
6153                 if (!next_eat_ws()) {
6154                     parseFailed(&QXmlSimpleReaderPrivate::parseElementDecl, state);
6155                     return false;
6156                 }
6157                 break;
6158             case Done:
6159                 next();
6160                 break;
6161         }
6162     }
6163     return false;
6164 }
6165 
6166 /*
6167   Parse a NotationDecl [82].
6168 
6169   Precondition: the beginning '<!' is already read and the head
6170   stands on the 'N' of '<!NOTATION'
6171 */
parseNotationDecl()6172 bool QXmlSimpleReaderPrivate::parseNotationDecl()
6173 {
6174     const signed char Init             = 0;
6175     const signed char Not              = 1; // read NOTATION
6176     const signed char Ws1              = 2; // eat whitespaces
6177     const signed char Nam              = 3; // read Name
6178     const signed char Ws2              = 4; // eat whitespaces
6179     const signed char ExtID            = 5; // parse ExternalID
6180     const signed char ExtIDR           = 6; // same as ExtID, but already reported
6181     const signed char Ws3              = 7; // eat whitespaces
6182     const signed char Done             = 8;
6183 
6184     const signed char InpWs            = 0;
6185     const signed char InpGt            = 1; // >
6186     const signed char InpN             = 2; // N
6187     const signed char InpUnknown       = 3;
6188 
6189     static const signed char table[8][4] = {
6190      /*  InpWs   InpGt  InpN    InpUnknown */
6191         { -1,     -1,    Not,    -1     }, // Init
6192         { Ws1,    -1,    -1,     -1     }, // Not
6193         { -1,     -1,    Nam,    Nam    }, // Ws1
6194         { Ws2,    Done,  -1,     -1     }, // Nam
6195         { -1,     Done,  ExtID,  ExtID  }, // Ws2
6196         { Ws3,    Done,  -1,     -1     }, // ExtID
6197         { Ws3,    Done,  -1,     -1     }, // ExtIDR
6198         { -1,     Done,  -1,     -1     }  // Ws3
6199     };
6200     signed char state;
6201     signed char input;
6202 
6203     if (parseStack == nullptr || parseStack->isEmpty()) {
6204         state = Init;
6205     } else {
6206         state = parseStack->pop().state;
6207 #if defined(QT_QXML_DEBUG)
6208         qDebug("QXmlSimpleReader: parseNotationDecl (cont) in state %d", state);
6209 #endif
6210         if (!parseStack->isEmpty()) {
6211             ParseFunction function = parseStack->top().function;
6212             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6213                 parseStack->pop();
6214 #if defined(QT_QXML_DEBUG)
6215                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6216 #endif
6217             }
6218             if (!(this->*function)()) {
6219                 parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6220                 return false;
6221             }
6222         }
6223     }
6224 
6225     for (;;) {
6226         switch (state) {
6227             case ExtID:
6228                 // call the handler
6229                 if (dtdHnd) {
6230                     if (!dtdHnd->notationDecl(name(), publicId, systemId)) {
6231                         reportParseError(dtdHnd->errorString());
6232                         return false;
6233                     }
6234                 }
6235                 state = ExtIDR;
6236                 break;
6237             case Done:
6238                 return true;
6239             case -1:
6240                 // Error
6241                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
6242                 return false;
6243         }
6244 
6245         if (atEnd()) {
6246             unexpectedEof(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6247             return false;
6248         }
6249         if (is_S(c)) {
6250             input = InpWs;
6251         } else if (c == QLatin1Char('>')) {
6252             input = InpGt;
6253         } else if (c == QLatin1Char('N')) {
6254             input = InpN;
6255         } else {
6256             input = InpUnknown;
6257         }
6258         state = table[state][input];
6259 
6260         switch (state) {
6261             case Not:
6262                 parseString_s = QLatin1String("NOTATION");
6263                 if (!parseString()) {
6264                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6265                     return false;
6266                 }
6267                 break;
6268             case Ws1:
6269                 if (!eat_ws()) {
6270                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6271                     return false;
6272                 }
6273                 break;
6274             case Nam:
6275                 parseName_useRef = false;
6276                 if (!parseName()) {
6277                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6278                     return false;
6279                 }
6280                 break;
6281             case Ws2:
6282                 if (!eat_ws()) {
6283                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6284                     return false;
6285                 }
6286                 break;
6287             case ExtID:
6288             case ExtIDR:
6289                 parseExternalID_allowPublicID = true;
6290                 if (!parseExternalID()) {
6291                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6292                     return false;
6293                 }
6294                 break;
6295             case Ws3:
6296                 if (!eat_ws()) {
6297                     parseFailed(&QXmlSimpleReaderPrivate::parseNotationDecl, state);
6298                     return false;
6299                 }
6300                 break;
6301             case Done:
6302                 next();
6303                 break;
6304         }
6305     }
6306     return false;
6307 }
6308 
6309 /*
6310   Parse choice [49] or seq [50].
6311 
6312   Precondition: the beginning '('S? is already read and the head
6313   stands on the first non-whitespace character after it.
6314 */
parseChoiceSeq()6315 bool QXmlSimpleReaderPrivate::parseChoiceSeq()
6316 {
6317     const signed char Init             = 0;
6318     const signed char Ws1              = 1; // eat whitespace
6319     const signed char CoS              = 2; // choice or set
6320     const signed char Ws2              = 3; // eat whitespace
6321     const signed char More             = 4; // more cp to read
6322     const signed char Name             = 5; // read name
6323     const signed char Done             = 6; //
6324 
6325     const signed char InpWs            = 0; // S
6326     const signed char InpOp            = 1; // (
6327     const signed char InpCp            = 2; //)
6328     const signed char InpQm            = 3; // ?
6329     const signed char InpAst           = 4; // *
6330     const signed char InpPlus          = 5; // +
6331     const signed char InpPipe          = 6; // |
6332     const signed char InpComm          = 7; // ,
6333     const signed char InpUnknown       = 8;
6334 
6335     static const signed char table[6][9] = {
6336      /*  InpWs   InpOp  InpCp  InpQm  InpAst  InpPlus  InpPipe  InpComm  InpUnknown */
6337         { -1,     Ws1,   -1,    -1,    -1,     -1,      -1,      -1,      Name  }, // Init
6338         { -1,     CoS,   -1,    -1,    -1,     -1,      -1,      -1,      CoS   }, // Ws1
6339         { Ws2,    -1,    Done,  Ws2,   Ws2,    Ws2,     More,    More,    -1    }, // CS
6340         { -1,     -1,    Done,  -1,    -1,     -1,      More,    More,    -1    }, // Ws2
6341         { -1,     Ws1,   -1,    -1,    -1,     -1,      -1,      -1,      Name  }, // More (same as Init)
6342         { Ws2,    -1,    Done,  Ws2,   Ws2,    Ws2,     More,    More,    -1    }  // Name (same as CS)
6343     };
6344     signed char state;
6345     signed char input;
6346 
6347     if (parseStack == nullptr || parseStack->isEmpty()) {
6348         state = Init;
6349     } else {
6350         state = parseStack->pop().state;
6351 #if defined(QT_QXML_DEBUG)
6352         qDebug("QXmlSimpleReader: parseChoiceSeq (cont) in state %d", state);
6353 #endif
6354         if (!parseStack->isEmpty()) {
6355             ParseFunction function = parseStack->top().function;
6356             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6357                 parseStack->pop();
6358 #if defined(QT_QXML_DEBUG)
6359                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6360 #endif
6361             }
6362             if (!(this->*function)()) {
6363                 parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6364                 return false;
6365             }
6366         }
6367     }
6368 
6369     for (;;) {
6370         switch (state) {
6371             case Done:
6372                 return true;
6373             case -1:
6374                 // Error
6375                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
6376                 return false;
6377         }
6378 
6379         if (atEnd()) {
6380             unexpectedEof(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6381             return false;
6382         }
6383         if (is_S(c)) {
6384             input = InpWs;
6385         } else if (c == QLatin1Char('(')) {
6386             input = InpOp;
6387         } else if (c == QLatin1Char(')')) {
6388             input = InpCp;
6389         } else if (c == QLatin1Char('?')) {
6390             input = InpQm;
6391         } else if (c == QLatin1Char('*')) {
6392             input = InpAst;
6393         } else if (c == QLatin1Char('+')) {
6394             input = InpPlus;
6395         } else if (c == QLatin1Char('|')) {
6396             input = InpPipe;
6397         } else if (c == QLatin1Char(',')) {
6398             input = InpComm;
6399         } else {
6400             input = InpUnknown;
6401         }
6402         state = table[state][input];
6403 
6404         switch (state) {
6405             case Ws1:
6406                 if (!next_eat_ws()) {
6407                     parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6408                     return false;
6409                 }
6410                 break;
6411             case CoS:
6412                 if (!parseChoiceSeq()) {
6413                     parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6414                     return false;
6415                 }
6416                 break;
6417             case Ws2:
6418                 if (!next_eat_ws()) {
6419                     parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6420                     return false;
6421                 }
6422                 break;
6423             case More:
6424                 if (!next_eat_ws()) {
6425                     parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6426                     return false;
6427                 }
6428                 break;
6429             case Name:
6430                 parseName_useRef = false;
6431                 if (!parseName()) {
6432                     parseFailed(&QXmlSimpleReaderPrivate::parseChoiceSeq, state);
6433                     return false;
6434                 }
6435                 break;
6436             case Done:
6437                 next();
6438                 break;
6439         }
6440     }
6441     return false;
6442 }
6443 
isExpandedEntityValueTooLarge(QString * errorMessage)6444 bool QXmlSimpleReaderPrivate::isExpandedEntityValueTooLarge(QString *errorMessage)
6445 {
6446     QString entityNameBuffer;
6447 
6448     // For every entity, check how many times all entity names were referenced in its value.
6449     for (QMap<QString,QString>::const_iterator toSearchIt = entities.constBegin();
6450          toSearchIt != entities.constEnd();
6451          ++toSearchIt) {
6452         const QString &toSearch = toSearchIt.key();
6453 
6454         // Don't check the same entities twice.
6455         if (!literalEntitySizes.contains(toSearch)) {
6456             // The amount of characters that weren't entity names, but literals, like 'X'.
6457             QString leftOvers = entities.value(toSearch);
6458             // How many times was entityName referenced by toSearch?
6459             for (QMap<QString,QString>::const_iterator referencedIt = entities.constBegin();
6460                  referencedIt != entities.constEnd();
6461                  ++referencedIt) {
6462                 const QString &entityName = referencedIt.key();
6463 
6464                 for (int i = 0; i < leftOvers.size() && i != -1; ) {
6465                     entityNameBuffer = QLatin1Char('&') + entityName + QLatin1Char(';');
6466 
6467                     i = leftOvers.indexOf(entityNameBuffer, i);
6468                     if (i != -1) {
6469                         leftOvers.remove(i, entityName.size() + 2);
6470                         // The entityName we're currently trying to find was matched in this string; increase our count.
6471                         ++referencesToOtherEntities[toSearch][entityName];
6472                     }
6473                 }
6474             }
6475             literalEntitySizes[toSearch] = leftOvers.size();
6476         }
6477     }
6478 
6479     for (QHash<QString, QHash<QString, int> >::const_iterator entityIt = referencesToOtherEntities.constBegin();
6480          entityIt != referencesToOtherEntities.constEnd();
6481          ++entityIt) {
6482         const QString &entity = entityIt.key();
6483 
6484         QHash<QString, int>::iterator expandedIt = expandedSizes.find(entity);
6485         if (expandedIt == expandedSizes.end()) {
6486             expandedIt = expandedSizes.insert(entity, literalEntitySizes.value(entity));
6487             for (QHash<QString, int>::const_iterator referenceIt = entityIt->constBegin();
6488                  referenceIt != entityIt->constEnd();
6489                  ++referenceIt) {
6490                 const QString &referenceTo = referenceIt.key();
6491                 const int references = referencesToOtherEntities.value(entity).value(referenceTo);
6492                 // The total size of an entity's value is the expanded size of all of its referenced entities, plus its literal size.
6493                 *expandedIt += expandedSizes.value(referenceTo) * references + literalEntitySizes.value(referenceTo) * references;
6494             }
6495 
6496             if (*expandedIt > entityCharacterLimit) {
6497                 if (errorMessage) {
6498                     *errorMessage = QString::fromLatin1("The XML entity \"%1\" expands to a string that is too large to process (%2 characters > %3).")
6499                         .arg(entity, QString::number(*expandedIt), QString::number(entityCharacterLimit));
6500                 }
6501                 return true;
6502             }
6503         }
6504     }
6505     return false;
6506 }
6507 
6508 /*
6509   Parse a EntityDecl [70].
6510 
6511   Precondition: the beginning '<!E' is already read and the head
6512   stand on the 'N' of '<!ENTITY'
6513 */
parseEntityDecl()6514 bool QXmlSimpleReaderPrivate::parseEntityDecl()
6515 {
6516     const signed char Init             =  0;
6517     const signed char Ent              =  1; // parse "ENTITY"
6518     const signed char Ws1              =  2; // white space read
6519     const signed char Name             =  3; // parse name
6520     const signed char Ws2              =  4; // white space read
6521     const signed char EValue           =  5; // parse entity value
6522     const signed char EValueR          =  6; // same as EValue, but already reported
6523     const signed char ExtID            =  7; // parse ExternalID
6524     const signed char Ws3              =  8; // white space read
6525     const signed char Ndata            =  9; // parse "NDATA"
6526     const signed char Ws4              = 10; // white space read
6527     const signed char NNam             = 11; // parse name
6528     const signed char NNamR            = 12; // same as NNam, but already reported
6529     const signed char PEDec            = 13; // parse PEDecl
6530     const signed char Ws6              = 14; // white space read
6531     const signed char PENam            = 15; // parse name
6532     const signed char Ws7              = 16; // white space read
6533     const signed char PEVal            = 17; // parse entity value
6534     const signed char PEValR           = 18; // same as PEVal, but already reported
6535     const signed char PEEID            = 19; // parse ExternalID
6536     const signed char PEEIDR           = 20; // same as PEEID, but already reported
6537     const signed char WsE              = 21; // white space read
6538     const signed char Done             = 22;
6539     const signed char EDDone           = 23; // done, but also report an external, unparsed entity decl
6540 
6541     const signed char InpWs            = 0; // white space
6542     const signed char InpPer           = 1; // %
6543     const signed char InpQuot          = 2; // " or '
6544     const signed char InpGt            = 3; // >
6545     const signed char InpN             = 4; // N
6546     const signed char InpUnknown       = 5;
6547 
6548     static const signed char table[22][6] = {
6549      /*  InpWs  InpPer  InpQuot  InpGt  InpN    InpUnknown */
6550         { -1,    -1,     -1,      -1,    Ent,    -1      }, // Init
6551         { Ws1,   -1,     -1,      -1,    -1,     -1      }, // Ent
6552         { -1,    PEDec,  -1,      -1,    Name,   Name    }, // Ws1
6553         { Ws2,   -1,     -1,      -1,    -1,     -1      }, // Name
6554         { -1,    -1,     EValue,  -1,    -1,     ExtID   }, // Ws2
6555         { WsE,   -1,     -1,      Done,  -1,     -1      }, // EValue
6556         { WsE,   -1,     -1,      Done,  -1,     -1      }, // EValueR
6557         { Ws3,   -1,     -1,      EDDone,-1,     -1      }, // ExtID
6558         { -1,    -1,     -1,      EDDone,Ndata,  -1      }, // Ws3
6559         { Ws4,   -1,     -1,      -1,    -1,     -1      }, // Ndata
6560         { -1,    -1,     -1,      -1,    NNam,   NNam    }, // Ws4
6561         { WsE,   -1,     -1,      Done,  -1,     -1      }, // NNam
6562         { WsE,   -1,     -1,      Done,  -1,     -1      }, // NNamR
6563         { Ws6,   -1,     -1,      -1,    -1,     -1      }, // PEDec
6564         { -1,    -1,     -1,      -1,    PENam,  PENam   }, // Ws6
6565         { Ws7,   -1,     -1,      -1,    -1,     -1      }, // PENam
6566         { -1,    -1,     PEVal,   -1,    -1,     PEEID   }, // Ws7
6567         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEVal
6568         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEValR
6569         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEEID
6570         { WsE,   -1,     -1,      Done,  -1,     -1      }, // PEEIDR
6571         { -1,    -1,     -1,      Done,  -1,     -1      }  // WsE
6572     };
6573     signed char state;
6574     signed char input;
6575 
6576     if (parseStack == nullptr || parseStack->isEmpty()) {
6577         state = Init;
6578     } else {
6579         state = parseStack->pop().state;
6580 #if defined(QT_QXML_DEBUG)
6581         qDebug("QXmlSimpleReader: parseEntityDecl (cont) in state %d", state);
6582 #endif
6583         if (!parseStack->isEmpty()) {
6584             ParseFunction function = parseStack->top().function;
6585             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6586                 parseStack->pop();
6587 #if defined(QT_QXML_DEBUG)
6588                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6589 #endif
6590             }
6591             if (!(this->*function)()) {
6592                 parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6593                 return false;
6594             }
6595         }
6596     }
6597 
6598     for (;;) {
6599         switch (state) {
6600             case EValue:
6601                 if ( !entityExist(name())) {
6602                     QString errorMessage;
6603                     if (isExpandedEntityValueTooLarge(&errorMessage)) {
6604                         reportParseError(errorMessage);
6605                         return false;
6606                     }
6607 
6608                     entities.insert(name(), string());
6609                     if (declHnd) {
6610                         if (!declHnd->internalEntityDecl(name(), string())) {
6611                             reportParseError(declHnd->errorString());
6612                             return false;
6613                         }
6614                     }
6615                 }
6616                 state = EValueR;
6617                 break;
6618             case NNam:
6619                 if ( !entityExist(name())) {
6620                     externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, ref()));
6621                     if (dtdHnd) {
6622                         if (!dtdHnd->unparsedEntityDecl(name(), publicId, systemId, ref())) {
6623                             reportParseError(declHnd->errorString());
6624                             return false;
6625                         }
6626                     }
6627                 }
6628                 state = NNamR;
6629                 break;
6630             case PEVal:
6631                 if ( !entityExist(name())) {
6632                     parameterEntities.insert(name(), string());
6633                     if (declHnd) {
6634                         if (!declHnd->internalEntityDecl(QLatin1Char('%') + name(), string())) {
6635                             reportParseError(declHnd->errorString());
6636                             return false;
6637                         }
6638                     }
6639                 }
6640                 state = PEValR;
6641                 break;
6642             case PEEID:
6643                 if ( !entityExist(name())) {
6644                     externParameterEntities.insert(name(), QXmlSimpleReaderPrivate::ExternParameterEntity(publicId, systemId));
6645                     if (declHnd) {
6646                         if (!declHnd->externalEntityDecl(QLatin1Char('%') + name(), publicId, systemId)) {
6647                             reportParseError(declHnd->errorString());
6648                             return false;
6649                         }
6650                     }
6651                 }
6652                 state = PEEIDR;
6653                 break;
6654             case EDDone:
6655                 if ( !entityExist(name())) {
6656                     externEntities.insert(name(), QXmlSimpleReaderPrivate::ExternEntity(publicId, systemId, QString()));
6657                     if (declHnd) {
6658                         if (!declHnd->externalEntityDecl(name(), publicId, systemId)) {
6659                             reportParseError(declHnd->errorString());
6660                             return false;
6661                         }
6662                     }
6663                 }
6664                 return true;
6665             case Done:
6666                 return true;
6667             case -1:
6668                 // Error
6669                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
6670                 return false;
6671         }
6672 
6673         if (atEnd()) {
6674             unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6675             return false;
6676         }
6677         if (is_S(c)) {
6678             input = InpWs;
6679         } else if (c == QLatin1Char('%')) {
6680             input = InpPer;
6681         } else if (c == QLatin1Char('"') || c == QLatin1Char('\'')) {
6682             input = InpQuot;
6683         } else if (c == QLatin1Char('>')) {
6684             input = InpGt;
6685         } else if (c == QLatin1Char('N')) {
6686             input = InpN;
6687         } else {
6688             input = InpUnknown;
6689         }
6690         state = table[state][input];
6691 
6692         switch (state) {
6693             case Ent:
6694                 parseString_s = QLatin1String("NTITY");
6695                 if (!parseString()) {
6696                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6697                     return false;
6698                 }
6699                 break;
6700             case Ws1:
6701                 if (!eat_ws()) {
6702                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6703                     return false;
6704                 }
6705                 break;
6706             case Name:
6707                 parseName_useRef = false;
6708                 if (!parseName()) {
6709                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6710                     return false;
6711                 }
6712                 break;
6713             case Ws2:
6714                 if (!eat_ws()) {
6715                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6716                     return false;
6717                 }
6718                 break;
6719             case EValue:
6720             case EValueR:
6721                 if (!parseEntityValue()) {
6722                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6723                     return false;
6724                 }
6725                 break;
6726             case ExtID:
6727                 parseExternalID_allowPublicID = false;
6728                 if (!parseExternalID()) {
6729                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6730                     return false;
6731                 }
6732                 break;
6733             case Ws3:
6734                 if (!eat_ws()) {
6735                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6736                     return false;
6737                 }
6738                 break;
6739             case Ndata:
6740                 parseString_s = QLatin1String("NDATA");
6741                 if (!parseString()) {
6742                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6743                     return false;
6744                 }
6745                 break;
6746             case Ws4:
6747                 if (!eat_ws()) {
6748                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6749                     return false;
6750                 }
6751                 break;
6752             case NNam:
6753             case NNamR:
6754                 parseName_useRef = true;
6755                 if (!parseName()) {
6756                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6757                     return false;
6758                 }
6759                 break;
6760             case PEDec:
6761                 next();
6762                 break;
6763             case Ws6:
6764                 if (!eat_ws()) {
6765                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6766                     return false;
6767                 }
6768                 break;
6769             case PENam:
6770                 parseName_useRef = false;
6771                 if (!parseName()) {
6772                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6773                     return false;
6774                 }
6775                 break;
6776             case Ws7:
6777                 if (!eat_ws()) {
6778                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6779                     return false;
6780                 }
6781                 break;
6782             case PEVal:
6783             case PEValR:
6784                 if (!parseEntityValue()) {
6785                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6786                     return false;
6787                 }
6788                 break;
6789             case PEEID:
6790             case PEEIDR:
6791                 parseExternalID_allowPublicID = false;
6792                 if (!parseExternalID()) {
6793                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6794                     return false;
6795                 }
6796                 break;
6797             case WsE:
6798                 if (!eat_ws()) {
6799                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityDecl, state);
6800                     return false;
6801                 }
6802                 break;
6803             case EDDone:
6804                 next();
6805                 break;
6806             case Done:
6807                 next();
6808                 break;
6809         }
6810     }
6811     return false;
6812 }
6813 
6814 /*
6815   Parse a EntityValue [9]
6816 */
parseEntityValue()6817 bool QXmlSimpleReaderPrivate::parseEntityValue()
6818 {
6819     const signed char Init             = 0;
6820     const signed char Dq               = 1; // EntityValue is double quoted
6821     const signed char DqC              = 2; // signed character
6822     const signed char DqPER            = 3; // PERefence
6823     const signed char DqRef            = 4; // Reference
6824     const signed char Sq               = 5; // EntityValue is double quoted
6825     const signed char SqC              = 6; // signed character
6826     const signed char SqPER            = 7; // PERefence
6827     const signed char SqRef            = 8; // Reference
6828     const signed char Done             = 9;
6829 
6830     const signed char InpDq            = 0; // "
6831     const signed char InpSq            = 1; // '
6832     const signed char InpAmp           = 2; // &
6833     const signed char InpPer           = 3; // %
6834     const signed char InpUnknown       = 4;
6835 
6836     static const signed char table[9][5] = {
6837      /*  InpDq  InpSq  InpAmp  InpPer  InpUnknown */
6838         { Dq,    Sq,    -1,     -1,     -1    }, // Init
6839         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // Dq
6840         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqC
6841         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqPER
6842         { Done,  DqC,   DqRef,  DqPER,  DqC   }, // DqRef
6843         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // Sq
6844         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // SqC
6845         { SqC,   Done,  SqRef,  SqPER,  SqC   }, // SqPER
6846         { SqC,   Done,  SqRef,  SqPER,  SqC   }  // SqRef
6847     };
6848     signed char state;
6849     signed char input;
6850 
6851     if (parseStack == nullptr || parseStack->isEmpty()) {
6852         state = Init;
6853     } else {
6854         state = parseStack->pop().state;
6855 #if defined(QT_QXML_DEBUG)
6856         qDebug("QXmlSimpleReader: parseEntityValue (cont) in state %d", state);
6857 #endif
6858         if (!parseStack->isEmpty()) {
6859             ParseFunction function = parseStack->top().function;
6860             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6861                 parseStack->pop();
6862 #if defined(QT_QXML_DEBUG)
6863                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6864 #endif
6865             }
6866             if (!(this->*function)()) {
6867                 parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state);
6868                 return false;
6869             }
6870         }
6871     }
6872 
6873     for (;;) {
6874         switch (state) {
6875             case Done:
6876                 return true;
6877             case -1:
6878                 // Error
6879                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
6880                 return false;
6881         }
6882 
6883         if (atEnd()) {
6884             unexpectedEof(&QXmlSimpleReaderPrivate::parseEntityValue, state);
6885             return false;
6886         }
6887         if        (c == QLatin1Char('"')) {
6888             input = InpDq;
6889         } else if (c == QLatin1Char('\'')) {
6890             input = InpSq;
6891         } else if (c == QLatin1Char('&')) {
6892             input = InpAmp;
6893         } else if (c == QLatin1Char('%')) {
6894             input = InpPer;
6895         } else {
6896             input = InpUnknown;
6897         }
6898         state = table[state][input];
6899 
6900         switch (state) {
6901             case Dq:
6902             case Sq:
6903                 stringClear();
6904                 next();
6905                 break;
6906             case DqC:
6907             case SqC:
6908                 stringAddC();
6909                 next();
6910                 break;
6911             case DqPER:
6912             case SqPER:
6913                 parsePEReference_context = InEntityValue;
6914                 if (!parsePEReference()) {
6915                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state);
6916                     return false;
6917                 }
6918                 break;
6919             case DqRef:
6920             case SqRef:
6921                 parseReference_context = InEntityValue;
6922                 if (!parseReference()) {
6923                     parseFailed(&QXmlSimpleReaderPrivate::parseEntityValue, state);
6924                     return false;
6925                 }
6926                 break;
6927             case Done:
6928                 next();
6929                 break;
6930         }
6931     }
6932     return false;
6933 }
6934 
6935 /*
6936   Parse a comment [15].
6937 
6938   Precondition: the beginning '<!' of the comment is already read and the head
6939   stands on the first '-' of '<!--'.
6940 
6941   If this funktion was successful, the head-position is on the first
6942   character after the comment.
6943 */
parseComment()6944 bool QXmlSimpleReaderPrivate::parseComment()
6945 {
6946     const signed char Init             = 0;
6947     const signed char Dash1            = 1; // the first dash was read
6948     const signed char Dash2            = 2; // the second dash was read
6949     const signed char Com              = 3; // read comment
6950     const signed char Com2             = 4; // read comment (help state)
6951     const signed char ComE             = 5; // finished reading comment
6952     const signed char Done             = 6;
6953 
6954     const signed char InpDash          = 0; // -
6955     const signed char InpGt            = 1; // >
6956     const signed char InpUnknown       = 2;
6957 
6958     static const signed char table[6][3] = {
6959      /*  InpDash  InpGt  InpUnknown */
6960         { Dash1,   -1,    -1  }, // Init
6961         { Dash2,   -1,    -1  }, // Dash1
6962         { Com2,    Com,   Com }, // Dash2
6963         { Com2,    Com,   Com }, // Com
6964         { ComE,    Com,   Com }, // Com2
6965         { -1,      Done,  -1  }  // ComE
6966     };
6967     signed char state;
6968     signed char input;
6969 
6970     if (parseStack == nullptr || parseStack->isEmpty()) {
6971         state = Init;
6972     } else {
6973         state = parseStack->pop().state;
6974 #if defined(QT_QXML_DEBUG)
6975         qDebug("QXmlSimpleReader: parseComment (cont) in state %d", state);
6976 #endif
6977         if (!parseStack->isEmpty()) {
6978             ParseFunction function = parseStack->top().function;
6979             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
6980                 parseStack->pop();
6981 #if defined(QT_QXML_DEBUG)
6982                 qDebug("QXmlSimpleReader: eat_ws (cont)");
6983 #endif
6984             }
6985             if (!(this->*function)()) {
6986                 parseFailed(&QXmlSimpleReaderPrivate::parseComment, state);
6987                 return false;
6988             }
6989         }
6990     }
6991 
6992     for (;;) {
6993         switch (state) {
6994             case Dash2:
6995                 stringClear();
6996                 break;
6997             case Com2:
6998                 // if next character is not a dash than don't skip it
6999                 if (!atEnd() && c != QLatin1Char('-'))
7000                     stringAddC(QLatin1Char('-'));
7001                 break;
7002             case Done:
7003                 return true;
7004             case -1:
7005                 // Error
7006                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGCOMMENT));
7007                 return false;
7008         }
7009 
7010         if (atEnd()) {
7011             unexpectedEof(&QXmlSimpleReaderPrivate::parseComment, state);
7012             return false;
7013         }
7014         if (c == QLatin1Char('-')) {
7015             input = InpDash;
7016         } else if (c == QLatin1Char('>')) {
7017             input = InpGt;
7018         } else {
7019             input = InpUnknown;
7020         }
7021         state = table[state][input];
7022 
7023         switch (state) {
7024             case Dash1:
7025                 next();
7026                 break;
7027             case Dash2:
7028                 next();
7029                 break;
7030             case Com:
7031                 stringAddC();
7032                 next();
7033                 break;
7034             case Com2:
7035                 next();
7036                 break;
7037             case ComE:
7038                 next();
7039                 break;
7040             case Done:
7041                 next();
7042                 break;
7043         }
7044     }
7045     return false;
7046 }
7047 
7048 /*
7049     Parse an Attribute [41].
7050 
7051     Precondition: the head stands on the first character of the name
7052     of the attribute (i.e. all whitespaces are already parsed).
7053 
7054     The head stand on the next character after the end quotes. The
7055     variable name contains the name of the attribute and the variable
7056     string contains the value of the attribute.
7057 */
parseAttribute()7058 bool QXmlSimpleReaderPrivate::parseAttribute()
7059 {
7060     const int Init             = 0;
7061     const int PName            = 1; // parse name
7062     const int Ws               = 2; // eat ws
7063     const int Eq               = 3; // the '=' was read
7064     const int Quotes           = 4; // " or ' were read
7065 
7066     const int InpNameBe        = 0;
7067     const int InpEq            = 1; // =
7068     const int InpDq            = 2; // "
7069     const int InpSq            = 3; // '
7070     const int InpUnknown       = 4;
7071 
7072     static const int table[4][5] = {
7073      /*  InpNameBe  InpEq  InpDq    InpSq    InpUnknown */
7074         { PName,     -1,    -1,      -1,      -1    }, // Init
7075         { -1,        Eq,    -1,      -1,      Ws    }, // PName
7076         { -1,        Eq,    -1,      -1,      -1    }, // Ws
7077         { -1,        -1,    Quotes,  Quotes,  -1    }  // Eq
7078     };
7079     int state;
7080     int input;
7081 
7082     if (parseStack == nullptr || parseStack->isEmpty()) {
7083         state = Init;
7084     } else {
7085         state = parseStack->pop().state;
7086 #if defined(QT_QXML_DEBUG)
7087         qDebug("QXmlSimpleReader: parseAttribute (cont) in state %d", state);
7088 #endif
7089         if (!parseStack->isEmpty()) {
7090             ParseFunction function = parseStack->top().function;
7091             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
7092                 parseStack->pop();
7093 #if defined(QT_QXML_DEBUG)
7094                 qDebug("QXmlSimpleReader: eat_ws (cont)");
7095 #endif
7096             }
7097             if (!(this->*function)()) {
7098                 parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
7099                 return false;
7100             }
7101         }
7102     }
7103 
7104     for (;;) {
7105         switch (state) {
7106             case Quotes:
7107                 // Done
7108                 return true;
7109             case -1:
7110                 // Error
7111                 reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
7112                 return false;
7113         }
7114 
7115         if (atEnd()) {
7116             unexpectedEof(&QXmlSimpleReaderPrivate::parseAttribute, state);
7117             return false;
7118         }
7119         if (determineNameChar(c) == NameBeginning) {
7120             input = InpNameBe;
7121         } else if (c == QLatin1Char('=')) {
7122             input = InpEq;
7123         } else if (c == QLatin1Char('"')) {
7124             input = InpDq;
7125         } else if (c == QLatin1Char('\'')) {
7126             input = InpSq;
7127         } else {
7128             input = InpUnknown;
7129         }
7130         state = table[state][input];
7131 
7132         switch (state) {
7133             case PName:
7134                 parseName_useRef = false;
7135                 if (!parseName()) {
7136                     parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
7137                     return false;
7138                 }
7139                 break;
7140             case Ws:
7141                 if (!eat_ws()) {
7142                     parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
7143                     return false;
7144                 }
7145                 break;
7146             case Eq:
7147                 if (!next_eat_ws()) {
7148                     parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
7149                     return false;
7150                 }
7151                 break;
7152             case Quotes:
7153                 if (!parseAttValue()) {
7154                     parseFailed(&QXmlSimpleReaderPrivate::parseAttribute, state);
7155                     return false;
7156                 }
7157                 break;
7158         }
7159     }
7160     return false;
7161 }
7162 
7163 /*
7164   Parse a Name [5] and store the name in name or ref (if useRef is true).
7165 */
parseName()7166 bool QXmlSimpleReaderPrivate::parseName()
7167 {
7168     const int Init             = 0;
7169     const int Name1            = 1; // parse first character of the name
7170     const int Name             = 2; // parse name
7171     const int Done             = 3;
7172 
7173     static const int table[3][3] = {
7174      /*  InpNameBe  InpNameCh  InpUnknown */
7175         { Name1,     -1,        -1    }, // Init
7176         { Name,      Name,      Done  }, // Name1
7177         { Name,      Name,      Done  }  // Name
7178     };
7179     int state;
7180 
7181     if (parseStack == nullptr || parseStack->isEmpty()) {
7182         state = Init;
7183     } else {
7184         state = parseStack->pop().state;
7185 #if defined(QT_QXML_DEBUG)
7186         qDebug("QXmlSimpleReader: parseName (cont) in state %d", state);
7187 #endif
7188         if (!parseStack->isEmpty()) {
7189             ParseFunction function = parseStack->top().function;
7190             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
7191                 parseStack->pop();
7192 #if defined(QT_QXML_DEBUG)
7193                 qDebug("QXmlSimpleReader: eat_ws (cont)");
7194 #endif
7195             }
7196             if (!(this->*function)()) {
7197                 parseFailed(&QXmlSimpleReaderPrivate::parseName, state);
7198                 return false;
7199             }
7200         }
7201     }
7202 
7203     for (;;) {
7204         switch (state) {
7205             case Done:
7206                 return true;
7207             case -1:
7208                 // Error
7209                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
7210                 return false;
7211         }
7212 
7213         if (atEnd()) {
7214             unexpectedEof(&QXmlSimpleReaderPrivate::parseName, state);
7215             return false;
7216         }
7217 
7218         // we can safely do the (int) cast thanks to the Q_ASSERTs earlier in this function
7219         state = table[state][(int)fastDetermineNameChar(c)];
7220 
7221         switch (state) {
7222             case Name1:
7223                 if (parseName_useRef) {
7224                     refClear();
7225                     refAddC();
7226                 } else {
7227                     nameClear();
7228                     nameAddC();
7229                 }
7230                 next();
7231                 break;
7232             case Name:
7233                 if (parseName_useRef) {
7234                     refAddC();
7235                 } else {
7236                     nameAddC();
7237                 }
7238                 next();
7239                 break;
7240         }
7241     }
7242     return false;
7243 }
7244 
7245 /*
7246   Parse a Nmtoken [7] and store the name in name.
7247 */
parseNmtoken()7248 bool QXmlSimpleReaderPrivate::parseNmtoken()
7249 {
7250     const signed char Init             = 0;
7251     const signed char NameF            = 1;
7252     const signed char Name             = 2;
7253     const signed char Done             = 3;
7254 
7255     const signed char InpNameCh        = 0; // NameChar without InpNameBe
7256     const signed char InpUnknown       = 1;
7257 
7258     static const signed char table[3][2] = {
7259      /*  InpNameCh  InpUnknown */
7260         { NameF,     -1    }, // Init
7261         { Name,      Done  }, // NameF
7262         { Name,      Done  }  // Name
7263     };
7264     signed char state;
7265     signed char input;
7266 
7267     if (parseStack == nullptr || parseStack->isEmpty()) {
7268         state = Init;
7269     } else {
7270         state = parseStack->pop().state;
7271 #if defined(QT_QXML_DEBUG)
7272         qDebug("QXmlSimpleReader: parseNmtoken (cont) in state %d", state);
7273 #endif
7274         if (!parseStack->isEmpty()) {
7275             ParseFunction function = parseStack->top().function;
7276             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
7277                 parseStack->pop();
7278 #if defined(QT_QXML_DEBUG)
7279                 qDebug("QXmlSimpleReader: eat_ws (cont)");
7280 #endif
7281             }
7282             if (!(this->*function)()) {
7283                 parseFailed(&QXmlSimpleReaderPrivate::parseNmtoken, state);
7284                 return false;
7285             }
7286         }
7287     }
7288 
7289     for (;;) {
7290         switch (state) {
7291             case Done:
7292                 return true;
7293             case -1:
7294                 // Error
7295                 reportParseError(QLatin1String(XMLERR_LETTEREXPECTED));
7296                 return false;
7297         }
7298 
7299         if (atEnd()) {
7300             unexpectedEof(&QXmlSimpleReaderPrivate::parseNmtoken, state);
7301             return false;
7302         }
7303         if (determineNameChar(c) == NotName) {
7304             input = InpUnknown;
7305         } else {
7306             input = InpNameCh;
7307         }
7308         state = table[state][input];
7309 
7310         switch (state) {
7311             case NameF:
7312                 nameClear();
7313                 nameAddC();
7314                 next();
7315                 break;
7316             case Name:
7317                 nameAddC();
7318                 next();
7319                 break;
7320         }
7321     }
7322     return false;
7323 }
7324 
7325 /*
7326   Parse a Reference [67].
7327 
7328   parseReference_charDataRead is set to true if the reference must not be
7329   parsed. The character(s) which the reference mapped to are appended to
7330   string. The head stands on the first character after the reference.
7331 
7332   parseReference_charDataRead is set to false if the reference must be parsed.
7333   The charachter(s) which the reference mapped to are inserted at the reference
7334   position. The head stands on the first character of the replacement).
7335 */
parseReference()7336 bool QXmlSimpleReaderPrivate::parseReference()
7337 {
7338     // temporary variables (only used in very local context, so they don't
7339     // interfere with incremental parsing)
7340     uint tmp;
7341     bool ok;
7342 
7343     const signed char Init             =  0;
7344     const signed char SRef             =  1; // start of a reference
7345     const signed char ChRef            =  2; // parse CharRef
7346     const signed char ChDec            =  3; // parse CharRef decimal
7347     const signed char ChHexS           =  4; // start CharRef hexadecimal
7348     const signed char ChHex            =  5; // parse CharRef hexadecimal
7349     const signed char Name             =  6; // parse name
7350     const signed char DoneD            =  7; // done CharRef decimal
7351     const signed char DoneH            =  8; // done CharRef hexadecimal
7352     const signed char DoneN            =  9; // done EntityRef
7353 
7354     const signed char InpAmp           = 0; // &
7355     const signed char InpSemi          = 1; // ;
7356     const signed char InpHash          = 2; // #
7357     const signed char InpX             = 3; // x
7358     const signed char InpNum           = 4; // 0-9
7359     const signed char InpHex           = 5; // a-f A-F
7360     const signed char InpUnknown       = 6;
7361 
7362     static const signed char table[8][7] = {
7363      /*  InpAmp  InpSemi  InpHash  InpX     InpNum  InpHex  InpUnknown */
7364         { SRef,   -1,      -1,      -1,      -1,     -1,     -1    }, // Init
7365         { -1,     -1,      ChRef,   Name,    Name,   Name,   Name  }, // SRef
7366         { -1,     -1,      -1,      ChHexS,  ChDec,  -1,     -1    }, // ChRef
7367         { -1,     DoneD,   -1,      -1,      ChDec,  -1,     -1    }, // ChDec
7368         { -1,     -1,      -1,      -1,      ChHex,  ChHex,  -1    }, // ChHexS
7369         { -1,     DoneH,   -1,      -1,      ChHex,  ChHex,  -1    }, // ChHex
7370         { -1,     DoneN,   -1,      -1,      -1,     -1,     -1    }  // Name
7371     };
7372     signed char state;
7373     signed char input;
7374 
7375     if (parseStack == nullptr || parseStack->isEmpty()) {
7376         parseReference_charDataRead = false;
7377         state = Init;
7378     } else {
7379         state = parseStack->pop().state;
7380 #if defined(QT_QXML_DEBUG)
7381         qDebug("QXmlSimpleReader: parseReference (cont) in state %d", state);
7382 #endif
7383         if (!parseStack->isEmpty()) {
7384             ParseFunction function = parseStack->top().function;
7385             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
7386                 parseStack->pop();
7387 #if defined(QT_QXML_DEBUG)
7388                 qDebug("QXmlSimpleReader: eat_ws (cont)");
7389 #endif
7390             }
7391             if (!(this->*function)()) {
7392                 parseFailed(&QXmlSimpleReaderPrivate::parseReference, state);
7393                 return false;
7394             }
7395         }
7396     }
7397 
7398     for (;;) {
7399         switch (state) {
7400             case DoneD:
7401                 return true;
7402             case DoneH:
7403                 return true;
7404             case DoneN:
7405                 return true;
7406             case -1:
7407                 // Error
7408                 reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
7409                 return false;
7410         }
7411 
7412         if (atEnd()) {
7413             unexpectedEof(&QXmlSimpleReaderPrivate::parseReference, state);
7414             return false;
7415         }
7416         if        (c.row()) {
7417             input = InpUnknown;
7418         } else if (c.cell() == '&') {
7419             input = InpAmp;
7420         } else if (c.cell() == ';') {
7421             input = InpSemi;
7422         } else if (c.cell() == '#') {
7423             input = InpHash;
7424         } else if (c.cell() == 'x') {
7425             input = InpX;
7426         } else if ('0' <= c.cell() && c.cell() <= '9') {
7427             input = InpNum;
7428         } else if ('a' <= c.cell() && c.cell() <= 'f') {
7429             input = InpHex;
7430         } else if ('A' <= c.cell() && c.cell() <= 'F') {
7431             input = InpHex;
7432         } else {
7433             input = InpUnknown;
7434         }
7435         state = table[state][input];
7436 
7437         switch (state) {
7438             case SRef:
7439                 refClear();
7440                 next();
7441                 break;
7442             case ChRef:
7443                 next();
7444                 break;
7445             case ChDec:
7446                 refAddC();
7447                 next();
7448                 break;
7449             case ChHexS:
7450                 next();
7451                 break;
7452             case ChHex:
7453                 refAddC();
7454                 next();
7455                 break;
7456             case Name:
7457                 // read the name into the ref
7458                 parseName_useRef = true;
7459                 if (!parseName()) {
7460                     parseFailed(&QXmlSimpleReaderPrivate::parseReference, state);
7461                     return false;
7462                 }
7463                 break;
7464             case DoneD:
7465                 tmp = ref().toUInt(&ok, 10);
7466                 if (ok) {
7467                     stringAddC(QChar(tmp));
7468                 } else {
7469                     reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
7470                     return false;
7471                 }
7472                 parseReference_charDataRead = true;
7473                 next();
7474                 break;
7475             case DoneH:
7476                 tmp = ref().toUInt(&ok, 16);
7477                 if (ok) {
7478                     stringAddC(QChar(tmp));
7479                 } else {
7480                     reportParseError(QLatin1String(XMLERR_ERRORPARSINGREFERENCE));
7481                     return false;
7482                 }
7483                 parseReference_charDataRead = true;
7484                 next();
7485                 break;
7486             case DoneN:
7487                 if (!processReference())
7488                     return false;
7489                 next();
7490                 break;
7491         }
7492     }
7493     return false;
7494 }
7495 
7496 /*
7497   Helper function for parseReference()
7498 */
processReference()7499 bool QXmlSimpleReaderPrivate::processReference()
7500 {
7501     QString reference = ref();
7502     if (reference == QLatin1String("amp")) {
7503         if (parseReference_context == InEntityValue) {
7504             // Bypassed
7505             stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('m')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char(';'));
7506         } else {
7507             // Included or Included in literal
7508             stringAddC(QLatin1Char('&'));
7509         }
7510         parseReference_charDataRead = true;
7511     } else if (reference == QLatin1String("lt")) {
7512         if (parseReference_context == InEntityValue) {
7513             // Bypassed
7514             stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('l')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
7515         } else {
7516             // Included or Included in literal
7517             stringAddC(QLatin1Char('<'));
7518         }
7519         parseReference_charDataRead = true;
7520     } else if (reference == QLatin1String("gt")) {
7521         if (parseReference_context == InEntityValue) {
7522             // Bypassed
7523             stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('g')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
7524         } else {
7525             // Included or Included in literal
7526             stringAddC(QLatin1Char('>'));
7527         }
7528         parseReference_charDataRead = true;
7529     } else if (reference == QLatin1String("apos")) {
7530         if (parseReference_context == InEntityValue) {
7531             // Bypassed
7532             stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('a')); stringAddC(QLatin1Char('p')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('s')); stringAddC(QLatin1Char(';'));
7533         } else {
7534             // Included or Included in literal
7535             stringAddC(QLatin1Char('\''));
7536         }
7537         parseReference_charDataRead = true;
7538     } else if (reference == QLatin1String("quot")) {
7539         if (parseReference_context == InEntityValue) {
7540             // Bypassed
7541             stringAddC(QLatin1Char('&')); stringAddC(QLatin1Char('q')); stringAddC(QLatin1Char('u')); stringAddC(QLatin1Char('o')); stringAddC(QLatin1Char('t')); stringAddC(QLatin1Char(';'));
7542         } else {
7543             // Included or Included in literal
7544             stringAddC(QLatin1Char('"'));
7545         }
7546         parseReference_charDataRead = true;
7547     } else {
7548         QMap<QString,QString>::Iterator it;
7549         it = entities.find(reference);
7550         if (it != entities.end()) {
7551             // "Internal General"
7552             switch (parseReference_context) {
7553                 case InContent:
7554                     // Included
7555                     if (!insertXmlRef(*it, reference, false))
7556                         return false;
7557                     parseReference_charDataRead = false;
7558                     break;
7559                 case InAttributeValue:
7560                     // Included in literal
7561                     if (!insertXmlRef(*it, reference, true))
7562                         return false;
7563                     parseReference_charDataRead = false;
7564                     break;
7565                 case InEntityValue:
7566                     {
7567                         // Bypassed
7568                         stringAddC(QLatin1Char('&'));
7569                         for (int i=0; i<(int)reference.length(); i++) {
7570                             stringAddC(reference[i]);
7571                         }
7572                         stringAddC(QLatin1Char(';'));
7573                         parseReference_charDataRead = true;
7574                     }
7575                     break;
7576                 case InDTD:
7577                     // Forbidden
7578                     parseReference_charDataRead = false;
7579                     reportParseError(QLatin1String(XMLERR_INTERNALGENERALENTITYINDTD));
7580                     return false;
7581             }
7582         } else {
7583             QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern;
7584             itExtern = externEntities.find(reference);
7585             if (itExtern == externEntities.end()) {
7586                 // entity not declared
7587                 // ### check this case for conformance
7588                 if (parseReference_context == InEntityValue) {
7589                     // Bypassed
7590                     stringAddC(QLatin1Char('&'));
7591                     for (int i=0; i<(int)reference.length(); i++) {
7592                         stringAddC(reference[i]);
7593                     }
7594                     stringAddC(QLatin1Char(';'));
7595                     parseReference_charDataRead = true;
7596                 } else {
7597                     // if we have some char data read, report it now
7598                     if (parseReference_context == InContent) {
7599                         if (contentCharDataRead) {
7600                             if (reportWhitespaceCharData || !string().simplified().isEmpty()) {
7601                                 if (contentHnd != nullptr && !contentHnd->characters(string())) {
7602                                     reportParseError(contentHnd->errorString());
7603                                     return false;
7604                                 }
7605                             }
7606                             stringClear();
7607                             contentCharDataRead = false;
7608                         }
7609                     }
7610 
7611                     if (contentHnd) {
7612                         skipped_entity_in_content = parseReference_context == InContent;
7613                         if (!contentHnd->skippedEntity(reference)) {
7614                             skipped_entity_in_content = false;
7615                             reportParseError(contentHnd->errorString());
7616                             return false; // error
7617                         }
7618                         skipped_entity_in_content = false;
7619                     }
7620                 }
7621             } else if ((*itExtern).notation.isNull()) {
7622                 // "External Parsed General"
7623                 switch (parseReference_context) {
7624                     case InContent:
7625                         {
7626                             // Included if validating
7627                             bool skipIt = true;
7628                             if (entityRes) {
7629 QT_WARNING_PUSH
7630 QT_WARNING_DISABLE_DEPRECATED
7631                                 QXmlInputSource *ret = nullptr;
7632 QT_WARNING_POP
7633                                 if (!entityRes->resolveEntity((*itExtern).publicId, (*itExtern).systemId, ret)) {
7634                                     delete ret;
7635                                     reportParseError(entityRes->errorString());
7636                                     return false;
7637                                 }
7638                                 if (ret) {
7639                                     QString xmlRefString;
7640                                     QString buffer = ret->data();
7641                                     while (!buffer.isEmpty()) {
7642                                         xmlRefString += buffer;
7643                                         ret->fetchData();
7644                                         buffer = ret->data();
7645                                     }
7646 
7647                                     delete ret;
7648                                     if (!stripTextDecl(xmlRefString)) {
7649                                         reportParseError(QLatin1String(XMLERR_ERRORINTEXTDECL));
7650                                         return false;
7651                                     }
7652                                     if (!insertXmlRef(xmlRefString, reference, false))
7653                                         return false;
7654                                     skipIt = false;
7655                                 }
7656                             }
7657                             if (skipIt && contentHnd) {
7658                                 skipped_entity_in_content = true;
7659                                 if (!contentHnd->skippedEntity(reference)) {
7660                                     skipped_entity_in_content = false;
7661                                     reportParseError(contentHnd->errorString());
7662                                     return false; // error
7663                                 }
7664                                 skipped_entity_in_content = false;
7665                             }
7666                             parseReference_charDataRead = false;
7667                         } break;
7668                     case InAttributeValue:
7669                         // Forbidden
7670                         parseReference_charDataRead = false;
7671                         reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINAV));
7672                         return false;
7673                     case InEntityValue:
7674                         {
7675                             // Bypassed
7676                             stringAddC(QLatin1Char('&'));
7677                             for (int i=0; i<(int)reference.length(); i++) {
7678                                 stringAddC(reference[i]);
7679                             }
7680                             stringAddC(QLatin1Char(';'));
7681                             parseReference_charDataRead = true;
7682                         }
7683                         break;
7684                     case InDTD:
7685                         // Forbidden
7686                         parseReference_charDataRead = false;
7687                         reportParseError(QLatin1String(XMLERR_EXTERNALGENERALENTITYINDTD));
7688                         return false;
7689                 }
7690             } else {
7691                 // "Unparsed"
7692                 // ### notify for "Occurs as Attribute Value" missing (but this is no refence, anyway)
7693                 // Forbidden
7694                 parseReference_charDataRead = false;
7695                 reportParseError(QLatin1String(XMLERR_UNPARSEDENTITYREFERENCE));
7696                 return false; // error
7697             }
7698         }
7699     }
7700     return true; // no error
7701 }
7702 
7703 
7704 /*
7705   Parses over a simple string.
7706 
7707   After the string was successfully parsed, the head is on the first
7708   character after the string.
7709 */
parseString()7710 bool QXmlSimpleReaderPrivate::parseString()
7711 {
7712     const signed char InpCharExpected  = 0; // the character that was expected
7713     const signed char InpUnknown       = 1;
7714 
7715     signed char state; // state in this function is the position in the string s
7716     signed char input;
7717 
7718     if (parseStack == nullptr || parseStack->isEmpty()) {
7719         Done = parseString_s.length();
7720         state = 0;
7721     } else {
7722         state = parseStack->pop().state;
7723 #if defined(QT_QXML_DEBUG)
7724         qDebug("QXmlSimpleReader: parseString (cont) in state %d", state);
7725 #endif
7726         if (!parseStack->isEmpty()) {
7727             ParseFunction function = parseStack->top().function;
7728             if (function == &QXmlSimpleReaderPrivate::eat_ws) {
7729                 parseStack->pop();
7730 #if defined(QT_QXML_DEBUG)
7731                 qDebug("QXmlSimpleReader: eat_ws (cont)");
7732 #endif
7733             }
7734             if (!(this->*function)()) {
7735                 parseFailed(&QXmlSimpleReaderPrivate::parseString, state);
7736                 return false;
7737             }
7738         }
7739     }
7740 
7741     for (;;) {
7742         if (state == Done) {
7743             return true;
7744         }
7745 
7746         if (atEnd()) {
7747             unexpectedEof(&QXmlSimpleReaderPrivate::parseString, state);
7748             return false;
7749         }
7750         if (c == parseString_s[(int)state]) {
7751             input = InpCharExpected;
7752         } else {
7753             input = InpUnknown;
7754         }
7755         if (input == InpCharExpected) {
7756             state++;
7757         } else {
7758             // Error
7759             reportParseError(QLatin1String(XMLERR_UNEXPECTEDCHARACTER));
7760             return false;
7761         }
7762 
7763         next();
7764     }
7765     return false;
7766 }
7767 
7768 /*
7769   This private function inserts and reports an entity substitution. The
7770   substituted string is \a data and the name of the entity reference is \a
7771   name. If \a inLiteral is true, the entity is IncludedInLiteral (i.e., " and '
7772   must be quoted. Otherwise they are not quoted.
7773 
7774   This function returns \c false on error.
7775 */
insertXmlRef(const QString & data,const QString & name,bool inLiteral)7776 bool QXmlSimpleReaderPrivate::insertXmlRef(const QString &data, const QString &name, bool inLiteral)
7777 {
7778     if (inLiteral) {
7779         QString tmp = data;
7780         xmlRefStack.push(XmlRef(name, tmp.replace(QLatin1Char('\"'),
7781                             QLatin1String("&quot;")).replace(QLatin1Char('\''), QLatin1String("&apos;"))));
7782     } else {
7783         xmlRefStack.push(XmlRef(name, data));
7784     }
7785     int n = qMax(parameterEntities.count(), entities.count());
7786     if (xmlRefStack.count() > n+1) {
7787         // recursive entities
7788         reportParseError(QLatin1String(XMLERR_RECURSIVEENTITIES));
7789         return false;
7790     }
7791     if (reportEntities && lexicalHnd) {
7792         if (!lexicalHnd->startEntity(name)) {
7793             reportParseError(lexicalHnd->errorString());
7794             return false;
7795         }
7796     }
7797     return true;
7798 }
7799 
7800 /*
7801   This private function moves the cursor to the next character.
7802 */
next()7803 void QXmlSimpleReaderPrivate::next()
7804 {
7805     int count = xmlRefStack.size();
7806     while (count != 0) {
7807         if (xmlRefStack.top().isEmpty()) {
7808             xmlRefStack.pop_back();
7809             count--;
7810         } else {
7811             c = xmlRefStack.top().next();
7812             return;
7813         }
7814     }
7815 
7816     // the following could be written nicer, but since it is a time-critical
7817     // function, rather optimize for speed
7818     ushort uc = c.unicode();
7819     c = inputSource->next();
7820     // If we are not incremental parsing, we just skip over EndOfData chars to give the
7821     // parser an uninterrupted stream of document chars.
7822     if (c == QChar(QXmlInputSource::EndOfData) && parseStack == nullptr)
7823         c = inputSource->next();
7824     if (uc == '\n') {
7825         lineNr++;
7826         columnNr = -1;
7827     } else if (uc == '\r') {
7828         if (c != QLatin1Char('\n')) {
7829             lineNr++;
7830             columnNr = -1;
7831         }
7832     }
7833     ++columnNr;
7834 }
7835 
7836 /*
7837   This private function moves the cursor to the next non-whitespace character.
7838   This function does not move the cursor if the actual cursor position is a
7839   non-whitespace charcter.
7840 
7841   Returns \c false when you use incremental parsing and this function reaches EOF
7842   with reading only whitespace characters. In this case it also poplulates the
7843   parseStack with useful information. In all other cases, this function returns
7844   true.
7845 */
eat_ws()7846 bool QXmlSimpleReaderPrivate::eat_ws()
7847 {
7848     while (!atEnd()) {
7849         if (!is_S(c)) {
7850             return true;
7851         }
7852         next();
7853     }
7854     if (parseStack != nullptr) {
7855         unexpectedEof(&QXmlSimpleReaderPrivate::eat_ws, 0);
7856         return false;
7857     }
7858     return true;
7859 }
7860 
next_eat_ws()7861 bool QXmlSimpleReaderPrivate::next_eat_ws()
7862 {
7863     next();
7864     return eat_ws();
7865 }
7866 
7867 
7868 /*
7869   This private function initializes the reader. \a i is the input source to
7870   read the data from.
7871 */
7872 QT_WARNING_PUSH
7873 QT_WARNING_DISABLE_DEPRECATED
init(const QXmlInputSource * i)7874 void QXmlSimpleReaderPrivate::init(const QXmlInputSource *i)
7875 {
7876     lineNr = 0;
7877     columnNr = -1;
7878     inputSource = const_cast<QXmlInputSource *>(i);
7879     initData();
7880 
7881     externParameterEntities.clear();
7882     parameterEntities.clear();
7883     externEntities.clear();
7884     entities.clear();
7885 
7886     clear(tags);
7887 
7888     doctype.clear();
7889     xmlVersion.clear();
7890     encoding.clear();
7891     standalone = QXmlSimpleReaderPrivate::Unknown;
7892     error.clear();
7893 }
7894 QT_WARNING_POP
7895 
7896 /*
7897   This private function initializes the XML data related variables. Especially,
7898   it reads the data from the input source.
7899 */
initData()7900 void QXmlSimpleReaderPrivate::initData()
7901 {
7902     c = QChar(QXmlInputSource::EndOfData);
7903     xmlRefStack.clear();
7904     next();
7905 }
7906 
7907 /*
7908   Returns \c true if a entity with the name \a e exists,
7909   otherwise returns \c false.
7910 */
entityExist(const QString & e) const7911 bool QXmlSimpleReaderPrivate::entityExist(const QString& e) const
7912 {
7913     if ( parameterEntities.find(e) == parameterEntities.end() &&
7914           externParameterEntities.find(e) == externParameterEntities.end() &&
7915           externEntities.find(e) == externEntities.end() &&
7916           entities.find(e) == entities.end()) {
7917         return false;
7918     } else {
7919         return true;
7920     }
7921 }
7922 
7923 QT_WARNING_PUSH
7924 QT_WARNING_DISABLE_DEPRECATED
reportParseError(const QString & error)7925 void QXmlSimpleReaderPrivate::reportParseError(const QString& error)
7926 {
7927     this->error = error;
7928     if (errorHnd) {
7929         if (this->error.isNull()) {
7930             const QXmlParseException ex(QLatin1String(XMLERR_OK), columnNr+1, lineNr+1,
7931                                         thisPublicId, thisSystemId);
7932             errorHnd->fatalError(ex);
7933         } else {
7934             const QXmlParseException ex(this->error, columnNr+1, lineNr+1,
7935                                         thisPublicId, thisSystemId);
7936             errorHnd->fatalError(ex);
7937         }
7938     }
7939 }
7940 QT_WARNING_POP
7941 
7942 /*
7943   This private function is called when a parsing function encounters an
7944   unexpected EOF. It decides what to do (depending on incremental parsing or
7945   not). \a where is a pointer to the function where the error occurred and \a
7946   state is the parsing state in this function.
7947 */
unexpectedEof(ParseFunction where,int state)7948 void QXmlSimpleReaderPrivate::unexpectedEof(ParseFunction where, int state)
7949 {
7950     if (parseStack == nullptr) {
7951         reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
7952     } else {
7953         if (c == QChar(QXmlInputSource::EndOfDocument)) {
7954             reportParseError(QLatin1String(XMLERR_UNEXPECTEDEOF));
7955         } else {
7956             pushParseState(where, state);
7957         }
7958     }
7959 }
7960 
7961 /*
7962   This private function is called when a parse...() function returned false. It
7963   determines if there was an error or if incremental parsing simply went out of
7964   data and does the right thing for the case. \a where is a pointer to the
7965   function where the error occurred and \a state is the parsing state in this
7966   function.
7967 */
parseFailed(ParseFunction where,int state)7968 void QXmlSimpleReaderPrivate::parseFailed(ParseFunction where, int state)
7969 {
7970     if (parseStack != nullptr && error.isNull()) {
7971         pushParseState(where, state);
7972     }
7973 }
7974 
7975 /*
7976   This private function pushes the function pointer \a function and state \a
7977   state to the parse stack. This is used when you are doing an incremental
7978   parsing and reach the end of file too early.
7979 
7980   Only call this function when d->parseStack!=0.
7981 */
pushParseState(ParseFunction function,int state)7982 void QXmlSimpleReaderPrivate::pushParseState(ParseFunction function, int state)
7983 {
7984     QXmlSimpleReaderPrivate::ParseState ps;
7985     ps.function = function;
7986     ps.state = state;
7987     parseStack->push(ps);
7988 }
7989 
updateValue(QString & value,const QChar * array,int & arrayPos,int & valueLen)7990 inline static void updateValue(QString &value, const QChar *array, int &arrayPos, int &valueLen)
7991 {
7992     value.resize(valueLen + arrayPos);
7993     memcpy(value.data() + valueLen, array, arrayPos * sizeof(QChar));
7994     valueLen += arrayPos;
7995     arrayPos = 0;
7996 }
7997 
7998 // use buffers instead of QString::operator+= when single characters are read
string()7999 const QString& QXmlSimpleReaderPrivate::string()
8000 {
8001     updateValue(stringValue, stringArray, stringArrayPos, stringValueLen);
8002     return stringValue;
8003 }
name()8004 const QString& QXmlSimpleReaderPrivate::name()
8005 {
8006     updateValue(nameValue, nameArray, nameArrayPos, nameValueLen);
8007     return nameValue;
8008 }
ref()8009 const QString& QXmlSimpleReaderPrivate::ref()
8010 {
8011     updateValue(refValue, refArray, refArrayPos, refValueLen);
8012     return refValue;
8013 }
8014 
stringAddC(QChar ch)8015 void QXmlSimpleReaderPrivate::stringAddC(QChar ch)
8016 {
8017     if (stringArrayPos == 256)
8018         updateValue(stringValue, stringArray, stringArrayPos, stringValueLen);
8019     stringArray[stringArrayPos++] = ch;
8020 }
nameAddC(QChar ch)8021 void QXmlSimpleReaderPrivate::nameAddC(QChar ch)
8022 {
8023     if (nameArrayPos == 256)
8024         updateValue(nameValue, nameArray, nameArrayPos, nameValueLen);
8025     nameArray[nameArrayPos++] = ch;
8026 }
refAddC(QChar ch)8027 void QXmlSimpleReaderPrivate::refAddC(QChar ch)
8028 {
8029     if (refArrayPos == 256)
8030         updateValue(refValue, refArray, refArrayPos, refValueLen);
8031     refArray[refArrayPos++] = ch;
8032 }
8033 QT_END_NAMESPACE
8034 
8035 #endif // QT_DEPRECATED_SINCE(5, 15)
8036