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

source code of qt5compat/src/core5/sax/qxml.cpp