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

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