/src/qtbase/src/xml/dom/qdomhelpers.cpp
Line | Count | Source |
1 | | /**************************************************************************** |
2 | | ** |
3 | | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | | ** Contact: https://www.qt.io/licensing/ |
5 | | ** |
6 | | ** This file is part of the QtXml module of the Qt Toolkit. |
7 | | ** |
8 | | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | | ** Commercial License Usage |
10 | | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | | ** accordance with the commercial license agreement provided with the |
12 | | ** Software or, alternatively, in accordance with the terms contained in |
13 | | ** a written agreement between you and The Qt Company. For licensing terms |
14 | | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | | ** information use the contact form at https://www.qt.io/contact-us. |
16 | | ** |
17 | | ** GNU Lesser General Public License Usage |
18 | | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | | ** General Public License version 3 as published by the Free Software |
20 | | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | | ** packaging of this file. Please review the following information to |
22 | | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | | ** |
25 | | ** GNU General Public License Usage |
26 | | ** Alternatively, this file may be used under the terms of the GNU |
27 | | ** General Public License version 2.0 or (at your option) the GNU General |
28 | | ** Public license version 3 or any later version approved by the KDE Free |
29 | | ** Qt Foundation. The licenses are as published by the Free Software |
30 | | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | | ** included in the packaging of this file. Please review the following |
32 | | ** information to ensure the GNU General Public License requirements will |
33 | | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | | ** |
36 | | ** $QT_END_LICENSE$ |
37 | | ** |
38 | | ****************************************************************************/ |
39 | | |
40 | | #include <QtXml/qtxmlglobal.h> |
41 | | |
42 | | #ifndef QT_NO_DOM |
43 | | |
44 | | #include "qdomhelpers_p.h" |
45 | | #include "qdom_p.h" |
46 | | #include "qxmlstream.h" |
47 | | #include "private/qxml_p.h" |
48 | | |
49 | | QT_BEGIN_NAMESPACE |
50 | | |
51 | | #if QT_DEPRECATED_SINCE(5, 15) |
52 | | |
53 | | /************************************************************** |
54 | | * |
55 | | * QDomHandler |
56 | | * |
57 | | **************************************************************/ |
58 | | QT_WARNING_PUSH |
59 | | QT_WARNING_DISABLE_DEPRECATED |
60 | | QDomHandler::QDomHandler(QDomDocumentPrivate *adoc, QXmlSimpleReader *areader, |
61 | | bool namespaceProcessing) |
62 | 0 | : cdata(false), reader(areader), domBuilder(adoc, &locator, namespaceProcessing) |
63 | 0 | { |
64 | 0 | } |
65 | | |
66 | 0 | QDomHandler::~QDomHandler() {} |
67 | | |
68 | | bool QDomHandler::endDocument() |
69 | 0 | { |
70 | 0 | return domBuilder.endDocument(); |
71 | 0 | } |
72 | | |
73 | | bool QDomHandler::startDTD(const QString &name, const QString &publicId, const QString &systemId) |
74 | 0 | { |
75 | 0 | return domBuilder.startDTD(name, publicId, systemId); |
76 | 0 | } |
77 | | |
78 | | bool QDomHandler::startElement(const QString &nsURI, const QString &, const QString &qName, |
79 | | const QXmlAttributes &atts) |
80 | 0 | { |
81 | 0 | return domBuilder.startElement(nsURI, qName, atts); |
82 | 0 | } |
83 | | |
84 | | bool QDomHandler::endElement(const QString &, const QString &, const QString &) |
85 | 0 | { |
86 | 0 | return domBuilder.endElement(); |
87 | 0 | } |
88 | | |
89 | | bool QDomHandler::characters(const QString &ch) |
90 | 0 | { |
91 | 0 | return domBuilder.characters(ch, cdata); |
92 | 0 | } |
93 | | |
94 | | bool QDomHandler::processingInstruction(const QString &target, const QString &data) |
95 | 0 | { |
96 | 0 | return domBuilder.processingInstruction(target, data); |
97 | 0 | } |
98 | | |
99 | | bool QDomHandler::skippedEntity(const QString &name) |
100 | 0 | { |
101 | | // we can only handle inserting entity references into content |
102 | 0 | if (reader && !reader->d_ptr->skipped_entity_in_content) |
103 | 0 | return true; |
104 | | |
105 | 0 | return domBuilder.skippedEntity(name); |
106 | 0 | } |
107 | | |
108 | | bool QDomHandler::fatalError(const QXmlParseException &exception) |
109 | 0 | { |
110 | 0 | domBuilder.errorMsg = exception.message(); |
111 | 0 | domBuilder.errorLine = exception.lineNumber(); |
112 | 0 | domBuilder.errorColumn = exception.columnNumber(); |
113 | 0 | return QXmlDefaultHandler::fatalError(exception); |
114 | 0 | } |
115 | | |
116 | | bool QDomHandler::startCDATA() |
117 | 0 | { |
118 | 0 | cdata = true; |
119 | 0 | return true; |
120 | 0 | } |
121 | | |
122 | | bool QDomHandler::endCDATA() |
123 | 0 | { |
124 | 0 | cdata = false; |
125 | 0 | return true; |
126 | 0 | } |
127 | | |
128 | | bool QDomHandler::startEntity(const QString &name) |
129 | 0 | { |
130 | 0 | return domBuilder.startEntity(name); |
131 | 0 | } |
132 | | |
133 | | bool QDomHandler::endEntity(const QString &) |
134 | 0 | { |
135 | 0 | return domBuilder.endEntity(); |
136 | 0 | } |
137 | | |
138 | | bool QDomHandler::comment(const QString &ch) |
139 | 0 | { |
140 | 0 | return domBuilder.comment(ch); |
141 | 0 | } |
142 | | |
143 | | bool QDomHandler::unparsedEntityDecl(const QString &name, const QString &publicId, |
144 | | const QString &systemId, const QString ¬ationName) |
145 | 0 | { |
146 | 0 | return domBuilder.unparsedEntityDecl(name, publicId, systemId, notationName); |
147 | 0 | } |
148 | | |
149 | | bool QDomHandler::externalEntityDecl(const QString &name, const QString &publicId, |
150 | | const QString &systemId) |
151 | 0 | { |
152 | 0 | return unparsedEntityDecl(name, publicId, systemId, QString()); |
153 | 0 | } |
154 | | |
155 | | bool QDomHandler::notationDecl(const QString &name, const QString &publicId, |
156 | | const QString &systemId) |
157 | 0 | { |
158 | 0 | return domBuilder.notationDecl(name, publicId, systemId); |
159 | 0 | } |
160 | | |
161 | | void QDomHandler::setDocumentLocator(QXmlLocator *locator) |
162 | 0 | { |
163 | 0 | this->locator.setLocator(locator); |
164 | 0 | } |
165 | | |
166 | | QDomBuilder::ErrorInfo QDomHandler::errorInfo() const |
167 | 0 | { |
168 | 0 | return domBuilder.error(); |
169 | 0 | } |
170 | | QT_WARNING_POP |
171 | | |
172 | | #endif // QT_DEPRECATED_SINCE(5, 15) |
173 | | |
174 | | /************************************************************** |
175 | | * |
176 | | * QXmlDocumentLocators |
177 | | * |
178 | | **************************************************************/ |
179 | | |
180 | | int QDomDocumentLocator::column() const |
181 | 0 | { |
182 | 0 | Q_ASSERT(reader); |
183 | 0 | return static_cast<int>(reader->columnNumber()); |
184 | 0 | } |
185 | | |
186 | | int QDomDocumentLocator::line() const |
187 | 0 | { |
188 | 0 | Q_ASSERT(reader); |
189 | 0 | return static_cast<int>(reader->lineNumber()); |
190 | 0 | } |
191 | | |
192 | | #if QT_DEPRECATED_SINCE(5, 15) |
193 | | |
194 | | QT_WARNING_PUSH |
195 | | QT_WARNING_DISABLE_DEPRECATED |
196 | | |
197 | | void QSAXDocumentLocator::setLocator(QXmlLocator *l) |
198 | 0 | { |
199 | 0 | locator = l; |
200 | 0 | } |
201 | | |
202 | | int QSAXDocumentLocator::column() const |
203 | 0 | { |
204 | 0 | if (!locator) |
205 | 0 | return 0; |
206 | | |
207 | 0 | return static_cast<int>(locator->columnNumber()); |
208 | 0 | } |
209 | | |
210 | | int QSAXDocumentLocator::line() const |
211 | 0 | { |
212 | 0 | if (!locator) |
213 | 0 | return 0; |
214 | | |
215 | 0 | return static_cast<int>(locator->lineNumber()); |
216 | 0 | } |
217 | | |
218 | | QT_WARNING_POP |
219 | | |
220 | | #endif // QT_DEPRECATED_SINCE(5, 15) |
221 | | |
222 | | /************************************************************** |
223 | | * |
224 | | * QDomBuilder |
225 | | * |
226 | | **************************************************************/ |
227 | | |
228 | | QDomBuilder::QDomBuilder(QDomDocumentPrivate *d, QXmlDocumentLocator *l, bool namespaceProcessing) |
229 | 0 | : errorLine(0), |
230 | 0 | errorColumn(0), |
231 | 0 | doc(d), |
232 | 0 | node(d), |
233 | 0 | locator(l), |
234 | 0 | nsProcessing(namespaceProcessing) |
235 | 0 | { |
236 | 0 | } |
237 | | |
238 | 0 | QDomBuilder::~QDomBuilder() {} |
239 | | |
240 | | bool QDomBuilder::endDocument() |
241 | 0 | { |
242 | | // ### is this really necessary? (rms) |
243 | 0 | if (node != doc) |
244 | 0 | return false; |
245 | 0 | return true; |
246 | 0 | } |
247 | | |
248 | | bool QDomBuilder::startDTD(const QString &name, const QString &publicId, const QString &systemId) |
249 | 0 | { |
250 | 0 | doc->doctype()->name = name; |
251 | 0 | doc->doctype()->publicId = publicId; |
252 | 0 | doc->doctype()->systemId = systemId; |
253 | 0 | return true; |
254 | 0 | } |
255 | | |
256 | | #if QT_DEPRECATED_SINCE(5, 15) |
257 | | |
258 | | QT_WARNING_PUSH |
259 | | QT_WARNING_DISABLE_DEPRECATED |
260 | | bool QDomBuilder::startElement(const QString &nsURI, const QString &qName, |
261 | | const QXmlAttributes &atts) |
262 | 0 | { |
263 | | // tag name |
264 | 0 | QDomNodePrivate *n; |
265 | 0 | if (nsProcessing) { |
266 | 0 | n = doc->createElementNS(nsURI, qName); |
267 | 0 | } else { |
268 | 0 | n = doc->createElement(qName); |
269 | 0 | } |
270 | |
|
271 | 0 | if (!n) |
272 | 0 | return false; |
273 | | |
274 | 0 | n->setLocation(locator->line(), locator->column()); |
275 | |
|
276 | 0 | node->appendChild(n); |
277 | 0 | node = n; |
278 | | |
279 | | // attributes |
280 | 0 | for (int i = 0; i < atts.length(); i++) { |
281 | 0 | auto domElement = static_cast<QDomElementPrivate *>(node); |
282 | 0 | if (nsProcessing) |
283 | 0 | domElement->setAttributeNS(atts.uri(i), atts.qName(i), atts.value(i)); |
284 | 0 | else |
285 | 0 | domElement->setAttribute(atts.qName(i), atts.value(i)); |
286 | 0 | } |
287 | |
|
288 | 0 | return true; |
289 | 0 | } |
290 | | QT_WARNING_POP |
291 | | |
292 | | #endif // QT_DEPRECATED_SINCE(5, 15) |
293 | | |
294 | | inline QString stringRefToString(const QStringRef &stringRef) |
295 | 0 | { |
296 | | // Calling QStringRef::toString() on a NULL QStringRef in some cases returns |
297 | | // an empty string (i.e. QString("")) instead of a NULL string (i.e. QString()). |
298 | | // QDom implementation differentiates between NULL and empty strings, so |
299 | | // we need this as workaround to keep the current behavior unchanged. |
300 | 0 | return stringRef.isNull() ? QString() : stringRef.toString(); |
301 | 0 | } |
302 | | |
303 | | QString QDomBuilder::dtdInternalSubset(const QString &dtd) |
304 | 0 | { |
305 | | // https://www.w3.org/TR/xml/#NT-intSubset |
306 | | // doctypedecl: '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' |
307 | 0 | const QString &name = doc->doctype()->name; |
308 | 0 | QStringView tmp = QStringView(dtd).mid(dtd.indexOf(name) + name.size()); |
309 | |
|
310 | 0 | const QString &publicId = doc->doctype()->publicId; |
311 | 0 | if (!publicId.isEmpty()) |
312 | 0 | tmp = tmp.mid(tmp.indexOf(publicId) + publicId.size()); |
313 | |
|
314 | 0 | const QString &systemId = doc->doctype()->systemId; |
315 | 0 | if (!systemId.isEmpty()) |
316 | 0 | tmp = tmp.mid(tmp.indexOf(systemId) + systemId.size()); |
317 | |
|
318 | 0 | const qsizetype obra = tmp.indexOf(u'['); |
319 | 0 | const qsizetype cbra = tmp.lastIndexOf(u']'); |
320 | 0 | if (obra >= 0 && cbra >= 0) |
321 | 0 | return tmp.left(cbra).mid(obra + 1).toString(); |
322 | | |
323 | 0 | return QString(); |
324 | 0 | } |
325 | | |
326 | | bool QDomBuilder::parseDTD(const QString &dtd) |
327 | 0 | { |
328 | 0 | doc->doctype()->internalSubset = dtdInternalSubset(dtd); |
329 | 0 | return true; |
330 | 0 | } |
331 | | |
332 | | bool QDomBuilder::startElement(const QString &nsURI, const QString &qName, |
333 | | const QXmlStreamAttributes &atts) |
334 | 0 | { |
335 | 0 | QDomNodePrivate *n = |
336 | 0 | nsProcessing ? doc->createElementNS(nsURI, qName) : doc->createElement(qName); |
337 | 0 | if (!n) |
338 | 0 | return false; |
339 | | |
340 | 0 | n->setLocation(locator->line(), locator->column()); |
341 | |
|
342 | 0 | node->appendChild(n); |
343 | 0 | node = n; |
344 | | |
345 | | // attributes |
346 | 0 | for (const auto &attr : atts) { |
347 | 0 | auto domElement = static_cast<QDomElementPrivate *>(node); |
348 | 0 | if (nsProcessing) { |
349 | 0 | domElement->setAttributeNS(stringRefToString(attr.namespaceUri()), |
350 | 0 | stringRefToString(attr.qualifiedName()), |
351 | 0 | stringRefToString(attr.value())); |
352 | 0 | } else { |
353 | 0 | domElement->setAttribute(stringRefToString(attr.qualifiedName()), |
354 | 0 | stringRefToString(attr.value())); |
355 | 0 | } |
356 | 0 | } |
357 | |
|
358 | 0 | return true; |
359 | 0 | } |
360 | | |
361 | | bool QDomBuilder::endElement() |
362 | 0 | { |
363 | 0 | if (!node || node == doc) |
364 | 0 | return false; |
365 | 0 | node = node->parent(); |
366 | |
|
367 | 0 | return true; |
368 | 0 | } |
369 | | |
370 | | bool QDomBuilder::characters(const QString &characters, bool cdata) |
371 | 0 | { |
372 | | // No text as child of some document |
373 | 0 | if (node == doc) |
374 | 0 | return false; |
375 | | |
376 | 0 | QScopedPointer<QDomNodePrivate> n; |
377 | 0 | if (cdata) { |
378 | 0 | n.reset(doc->createCDATASection(characters)); |
379 | 0 | } else if (!entityName.isEmpty()) { |
380 | 0 | QScopedPointer<QDomEntityPrivate> e( |
381 | 0 | new QDomEntityPrivate(doc, nullptr, entityName, QString(), QString(), QString())); |
382 | 0 | e->value = characters; |
383 | 0 | e->ref.deref(); |
384 | 0 | doc->doctype()->appendChild(e.data()); |
385 | 0 | e.take(); |
386 | 0 | n.reset(doc->createEntityReference(entityName)); |
387 | 0 | } else { |
388 | 0 | n.reset(doc->createTextNode(characters)); |
389 | 0 | } |
390 | 0 | n->setLocation(locator->line(), locator->column()); |
391 | 0 | node->appendChild(n.data()); |
392 | 0 | n.take(); |
393 | |
|
394 | 0 | return true; |
395 | 0 | } |
396 | | |
397 | | bool QDomBuilder::processingInstruction(const QString &target, const QString &data) |
398 | 0 | { |
399 | 0 | QDomNodePrivate *n; |
400 | 0 | n = doc->createProcessingInstruction(target, data); |
401 | 0 | if (n) { |
402 | 0 | n->setLocation(locator->line(), locator->column()); |
403 | 0 | node->appendChild(n); |
404 | 0 | return true; |
405 | 0 | } else |
406 | 0 | return false; |
407 | 0 | } |
408 | | |
409 | | bool QDomBuilder::skippedEntity(const QString &name) |
410 | 0 | { |
411 | 0 | QDomNodePrivate *n = doc->createEntityReference(name); |
412 | 0 | n->setLocation(locator->line(), locator->column()); |
413 | 0 | node->appendChild(n); |
414 | 0 | return true; |
415 | 0 | } |
416 | | |
417 | | void QDomBuilder::fatalError(const QString &message) |
418 | 0 | { |
419 | 0 | errorMsg = message; |
420 | 0 | errorLine = static_cast<int>(locator->line()); |
421 | 0 | errorColumn = static_cast<int>(locator->column()); |
422 | 0 | } |
423 | | |
424 | | QDomBuilder::ErrorInfo QDomBuilder::error() const |
425 | 0 | { |
426 | 0 | return ErrorInfo(errorMsg, errorLine, errorColumn); |
427 | 0 | } |
428 | | |
429 | | bool QDomBuilder::startEntity(const QString &name) |
430 | 0 | { |
431 | 0 | entityName = name; |
432 | 0 | return true; |
433 | 0 | } |
434 | | |
435 | | bool QDomBuilder::endEntity() |
436 | 0 | { |
437 | 0 | entityName.clear(); |
438 | 0 | return true; |
439 | 0 | } |
440 | | |
441 | | bool QDomBuilder::comment(const QString &characters) |
442 | 0 | { |
443 | 0 | QDomNodePrivate *n; |
444 | 0 | n = doc->createComment(characters); |
445 | 0 | n->setLocation(locator->line(), locator->column()); |
446 | 0 | node->appendChild(n); |
447 | 0 | return true; |
448 | 0 | } |
449 | | |
450 | | bool QDomBuilder::unparsedEntityDecl(const QString &name, const QString &publicId, |
451 | | const QString &systemId, const QString ¬ationName) |
452 | 0 | { |
453 | 0 | QDomEntityPrivate *e = |
454 | 0 | new QDomEntityPrivate(doc, nullptr, name, publicId, systemId, notationName); |
455 | | // keep the refcount balanced: appendChild() does a ref anyway. |
456 | 0 | e->ref.deref(); |
457 | 0 | doc->doctype()->appendChild(e); |
458 | 0 | return true; |
459 | 0 | } |
460 | | |
461 | | bool QDomBuilder::externalEntityDecl(const QString &name, const QString &publicId, |
462 | | const QString &systemId) |
463 | 0 | { |
464 | 0 | return unparsedEntityDecl(name, publicId, systemId, QString()); |
465 | 0 | } |
466 | | |
467 | | bool QDomBuilder::notationDecl(const QString &name, const QString &publicId, |
468 | | const QString &systemId) |
469 | 0 | { |
470 | 0 | QDomNotationPrivate *n = new QDomNotationPrivate(doc, nullptr, name, publicId, systemId); |
471 | | // keep the refcount balanced: appendChild() does a ref anyway. |
472 | 0 | n->ref.deref(); |
473 | 0 | doc->doctype()->appendChild(n); |
474 | 0 | return true; |
475 | 0 | } |
476 | | |
477 | | /************************************************************** |
478 | | * |
479 | | * QDomParser |
480 | | * |
481 | | **************************************************************/ |
482 | | |
483 | | QDomParser::QDomParser(QDomDocumentPrivate *d, QXmlStreamReader *r, bool namespaceProcessing) |
484 | 0 | : reader(r), locator(r), domBuilder(d, &locator, namespaceProcessing) |
485 | 0 | { |
486 | 0 | } |
487 | | |
488 | | bool QDomParser::parse() |
489 | 0 | { |
490 | 0 | return parseProlog() && parseBody(); |
491 | 0 | } |
492 | | |
493 | | QDomBuilder::ErrorInfo QDomParser::errorInfo() const |
494 | 0 | { |
495 | 0 | return domBuilder.error(); |
496 | 0 | } |
497 | | |
498 | | bool QDomParser::parseProlog() |
499 | 0 | { |
500 | 0 | Q_ASSERT(reader); |
501 | |
|
502 | 0 | bool foundDtd = false; |
503 | |
|
504 | 0 | while (!reader->atEnd()) { |
505 | 0 | reader->readNext(); |
506 | |
|
507 | 0 | if (reader->hasError()) { |
508 | 0 | domBuilder.fatalError(reader->errorString()); |
509 | 0 | return false; |
510 | 0 | } |
511 | | |
512 | 0 | switch (reader->tokenType()) { |
513 | 0 | case QXmlStreamReader::StartDocument: |
514 | 0 | if (!reader->documentVersion().isEmpty()) { |
515 | 0 | QString value(QLatin1String("version='")); |
516 | 0 | value += reader->documentVersion(); |
517 | 0 | value += QLatin1Char('\''); |
518 | 0 | if (!reader->documentEncoding().isEmpty()) { |
519 | 0 | value += QLatin1String(" encoding='"); |
520 | 0 | value += reader->documentEncoding(); |
521 | 0 | value += QLatin1Char('\''); |
522 | 0 | } |
523 | 0 | if (reader->isStandaloneDocument()) { |
524 | 0 | value += QLatin1String(" standalone='yes'"); |
525 | 0 | } else { |
526 | | // TODO: Add standalone='no', if 'standalone' is specified. With the current |
527 | | // QXmlStreamReader there is no way to figure out if it was specified or not. |
528 | | // QXmlStreamReader needs to be modified for handling that case correctly. |
529 | 0 | } |
530 | |
|
531 | 0 | if (!domBuilder.processingInstruction(QLatin1String("xml"), value)) { |
532 | 0 | domBuilder.fatalError( |
533 | 0 | QDomParser::tr("Error occurred while processing XML declaration")); |
534 | 0 | return false; |
535 | 0 | } |
536 | 0 | } |
537 | 0 | break; |
538 | 0 | case QXmlStreamReader::DTD: |
539 | 0 | if (foundDtd) { |
540 | 0 | domBuilder.fatalError(QDomParser::tr("Multiple DTD sections are not allowed")); |
541 | 0 | return false; |
542 | 0 | } |
543 | 0 | foundDtd = true; |
544 | |
|
545 | 0 | if (!domBuilder.startDTD(stringRefToString(reader->dtdName()), |
546 | 0 | stringRefToString(reader->dtdPublicId()), |
547 | 0 | stringRefToString(reader->dtdSystemId()))) { |
548 | 0 | domBuilder.fatalError( |
549 | 0 | QDomParser::tr("Error occurred while processing document type declaration")); |
550 | 0 | return false; |
551 | 0 | } |
552 | 0 | if (!domBuilder.parseDTD(reader->text().toString())) |
553 | 0 | return false; |
554 | 0 | if (!parseMarkupDecl()) |
555 | 0 | return false; |
556 | 0 | break; |
557 | 0 | case QXmlStreamReader::Comment: |
558 | 0 | if (!domBuilder.comment(reader->text().toString())) { |
559 | 0 | domBuilder.fatalError(QDomParser::tr("Error occurred while processing comment")); |
560 | 0 | return false; |
561 | 0 | } |
562 | 0 | break; |
563 | 0 | case QXmlStreamReader::ProcessingInstruction: |
564 | 0 | if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(), |
565 | 0 | reader->processingInstructionData().toString())) { |
566 | 0 | domBuilder.fatalError( |
567 | 0 | QDomParser::tr("Error occurred while processing a processing instruction")); |
568 | 0 | return false; |
569 | 0 | } |
570 | 0 | break; |
571 | 0 | default: |
572 | | // If the token is none of the above, prolog processing is done. |
573 | 0 | return true; |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | 0 | return true; |
578 | 0 | } |
579 | | |
580 | | bool QDomParser::parseBody() |
581 | 0 | { |
582 | 0 | Q_ASSERT(reader); |
583 | |
|
584 | 0 | std::stack<QStringRef> tagStack; |
585 | 0 | while (!reader->atEnd() && !reader->hasError()) { |
586 | 0 | switch (reader->tokenType()) { |
587 | 0 | case QXmlStreamReader::StartElement: |
588 | 0 | tagStack.push(reader->qualifiedName()); |
589 | 0 | if (!domBuilder.startElement(stringRefToString(reader->namespaceUri()), |
590 | 0 | stringRefToString(reader->qualifiedName()), |
591 | 0 | reader->attributes())) { |
592 | 0 | domBuilder.fatalError( |
593 | 0 | QDomParser::tr("Error occurred while processing a start element")); |
594 | 0 | return false; |
595 | 0 | } |
596 | 0 | break; |
597 | 0 | case QXmlStreamReader::EndElement: |
598 | 0 | if (tagStack.empty() || reader->qualifiedName() != tagStack.top()) { |
599 | 0 | domBuilder.fatalError( |
600 | 0 | QDomParser::tr("Unexpected end element '%1'").arg(reader->name())); |
601 | 0 | return false; |
602 | 0 | } |
603 | 0 | tagStack.pop(); |
604 | 0 | if (!domBuilder.endElement()) { |
605 | 0 | domBuilder.fatalError( |
606 | 0 | QDomParser::tr("Error occurred while processing an end element")); |
607 | 0 | return false; |
608 | 0 | } |
609 | 0 | break; |
610 | 0 | case QXmlStreamReader::Characters: |
611 | 0 | if (!reader->isWhitespace()) { // Skip the content consisting of only whitespaces |
612 | 0 | if (!reader->text().toString().trimmed().isEmpty()) { |
613 | 0 | if (!domBuilder.characters(reader->text().toString(), reader->isCDATA())) { |
614 | 0 | domBuilder.fatalError(QDomParser::tr( |
615 | 0 | "Error occurred while processing the element content")); |
616 | 0 | return false; |
617 | 0 | } |
618 | 0 | } |
619 | 0 | } |
620 | 0 | break; |
621 | 0 | case QXmlStreamReader::Comment: |
622 | 0 | if (!domBuilder.comment(reader->text().toString())) { |
623 | 0 | domBuilder.fatalError(QDomParser::tr("Error occurred while processing comments")); |
624 | 0 | return false; |
625 | 0 | } |
626 | 0 | break; |
627 | 0 | case QXmlStreamReader::ProcessingInstruction: |
628 | 0 | if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(), |
629 | 0 | reader->processingInstructionData().toString())) { |
630 | 0 | domBuilder.fatalError( |
631 | 0 | QDomParser::tr("Error occurred while processing a processing instruction")); |
632 | 0 | return false; |
633 | 0 | } |
634 | 0 | break; |
635 | 0 | case QXmlStreamReader::EntityReference: |
636 | 0 | if (!domBuilder.skippedEntity(reader->name().toString())) { |
637 | 0 | domBuilder.fatalError( |
638 | 0 | QDomParser::tr("Error occurred while processing an entity reference")); |
639 | 0 | return false; |
640 | 0 | } |
641 | 0 | break; |
642 | 0 | default: |
643 | 0 | domBuilder.fatalError(QDomParser::tr("Unexpected token")); |
644 | 0 | return false; |
645 | 0 | } |
646 | | |
647 | 0 | reader->readNext(); |
648 | 0 | } |
649 | | |
650 | 0 | if (reader->hasError()) { |
651 | 0 | domBuilder.fatalError(reader->errorString()); |
652 | 0 | reader->readNext(); |
653 | 0 | return false; |
654 | 0 | } |
655 | | |
656 | 0 | if (!tagStack.empty()) { |
657 | 0 | domBuilder.fatalError(QDomParser::tr("Tag mismatch")); |
658 | 0 | return false; |
659 | 0 | } |
660 | | |
661 | 0 | return true; |
662 | 0 | } |
663 | | |
664 | | bool QDomParser::parseMarkupDecl() |
665 | 0 | { |
666 | 0 | Q_ASSERT(reader); |
667 | |
|
668 | 0 | const auto entities = reader->entityDeclarations(); |
669 | 0 | for (const auto &entityDecl : entities) { |
670 | | // Entity declarations are created only for Extrenal Entities. Internal Entities |
671 | | // are parsed, and QXmlStreamReader handles the parsing itself and returns the |
672 | | // parsed result. So we don't need to do anything for the Internal Entities. |
673 | 0 | if (!entityDecl.publicId().isEmpty() || !entityDecl.systemId().isEmpty()) { |
674 | | // External Entity |
675 | 0 | if (!domBuilder.unparsedEntityDecl(stringRefToString(entityDecl.name()), |
676 | 0 | stringRefToString(entityDecl.publicId()), |
677 | 0 | stringRefToString(entityDecl.systemId()), |
678 | 0 | stringRefToString(entityDecl.notationName()))) { |
679 | 0 | domBuilder.fatalError( |
680 | 0 | QDomParser::tr("Error occurred while processing entity declaration")); |
681 | 0 | return false; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | } |
685 | | |
686 | 0 | const auto notations = reader->notationDeclarations(); |
687 | 0 | for (const auto ¬ationDecl : notations) { |
688 | 0 | if (!domBuilder.notationDecl(stringRefToString(notationDecl.name()), |
689 | 0 | stringRefToString(notationDecl.publicId()), |
690 | 0 | stringRefToString(notationDecl.systemId()))) { |
691 | 0 | domBuilder.fatalError( |
692 | 0 | QDomParser::tr("Error occurred while processing notation declaration")); |
693 | 0 | return false; |
694 | 0 | } |
695 | 0 | } |
696 | | |
697 | 0 | return true; |
698 | 0 | } |
699 | | |
700 | | QT_END_NAMESPACE |
701 | | |
702 | | #endif // QT_NO_DOM |