1 /*
2 * Copyright (C) 2000 Peter Kelly (pmk@post.com)
3 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
5 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7 * Copyright (C) 2008 Holger Hans Peter Freyther
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "config.h"
27 #include "XMLDocumentParser.h"
28
29 #include "CDATASection.h"
30 #include "CachedScript.h"
31 #include "Comment.h"
32 #include "CachedResourceLoader.h"
33 #include "Document.h"
34 #include "DocumentFragment.h"
35 #include "DocumentType.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "FrameView.h"
39 #include "HTMLEntityParser.h"
40 #include "HTMLHtmlElement.h"
41 #include "HTMLLinkElement.h"
42 #include "HTMLNames.h"
43 #include "HTMLStyleElement.h"
44 #include "ProcessingInstruction.h"
45 #include "ResourceError.h"
46 #include "ResourceHandle.h"
47 #include "ResourceRequest.h"
48 #include "ResourceResponse.h"
49 #include "ScriptableDocumentParser.h"
50 #include "ScriptElement.h"
51 #include "ScriptSourceCode.h"
52 #include "ScriptValue.h"
53 #include "TextResourceDecoder.h"
54 #include "TransformSource.h"
55 #include <QDebug>
56 #include <wtf/StringExtras.h>
57 #include <wtf/Threading.h>
58 #include <wtf/Vector.h>
59 #include <wtf/text/CString.h>
60
61 #if ENABLE(XHTMLMP)
62 #include "HTMLNames.h"
63 #include "HTMLScriptElement.h"
64 #endif
65
66 using namespace std;
67
68 namespace WebCore {
69
70 class EntityResolver : public QXmlStreamEntityResolver {
71 virtual QString resolveUndeclaredEntity(const QString &name);
72 };
73
resolveUndeclaredEntity(const QString & name)74 QString EntityResolver::resolveUndeclaredEntity(const QString &name)
75 {
76 UChar c = decodeNamedEntity(name.toUtf8().constData());
77 return QString(c);
78 }
79
80 // --------------------------------
81
supportsXMLVersion(const String & version)82 bool XMLDocumentParser::supportsXMLVersion(const String& version)
83 {
84 return version == "1.0";
85 }
86
XMLDocumentParser(Document * document,FrameView * frameView)87 XMLDocumentParser::XMLDocumentParser(Document* document, FrameView* frameView)
88 : ScriptableDocumentParser(document)
89 , m_view(frameView)
90 , m_wroteText(false)
91 , m_currentNode(document)
92 , m_sawError(false)
93 , m_sawCSS(false)
94 , m_sawXSLTransform(false)
95 , m_sawFirstElement(false)
96 , m_isXHTMLDocument(false)
97 #if ENABLE(XHTMLMP)
98 , m_isXHTMLMPDocument(false)
99 , m_hasDocTypeDeclaration(false)
100 #endif
101 , m_parserPaused(false)
102 , m_requestingScript(false)
103 , m_finishCalled(false)
104 , m_errorCount(0)
105 , m_lastErrorPosition(TextPosition1::belowRangePosition())
106 , m_pendingScript(0)
107 , m_scriptStartPosition(TextPosition1::belowRangePosition())
108 , m_parsingFragment(false)
109 , m_scriptingPermission(FragmentScriptingAllowed)
110 {
111 m_stream.setEntityResolver(new EntityResolver);
112 }
113
XMLDocumentParser(DocumentFragment * fragment,Element * parentElement,FragmentScriptingPermission permission)114 XMLDocumentParser::XMLDocumentParser(DocumentFragment* fragment, Element* parentElement, FragmentScriptingPermission permission)
115 : ScriptableDocumentParser(fragment->document())
116 , m_view(0)
117 , m_wroteText(false)
118 , m_currentNode(fragment)
119 , m_sawError(false)
120 , m_sawCSS(false)
121 , m_sawXSLTransform(false)
122 , m_sawFirstElement(false)
123 , m_isXHTMLDocument(false)
124 #if ENABLE(XHTMLMP)
125 , m_isXHTMLMPDocument(false)
126 , m_hasDocTypeDeclaration(false)
127 #endif
128 , m_parserPaused(false)
129 , m_requestingScript(false)
130 , m_finishCalled(false)
131 , m_errorCount(0)
132 , m_lastErrorPosition(TextPosition1::belowRangePosition())
133 , m_pendingScript(0)
134 , m_scriptStartPosition(TextPosition1::belowRangePosition())
135 , m_parsingFragment(true)
136 , m_scriptingPermission(permission)
137 {
138 fragment->ref();
139
140 // Add namespaces based on the parent node
141 Vector<Element*> elemStack;
142 while (parentElement) {
143 elemStack.append(parentElement);
144
145 Node* n = parentElement->parentNode();
146 if (!n || !n->isElementNode())
147 break;
148 parentElement = static_cast<Element*>(n);
149 }
150
151 if (elemStack.isEmpty())
152 return;
153
154 QXmlStreamNamespaceDeclarations namespaces;
155 for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
156 if (NamedNodeMap* attrs = element->attributes()) {
157 for (unsigned i = 0; i < attrs->length(); i++) {
158 Attribute* attr = attrs->attributeItem(i);
159 if (attr->localName() == "xmlns")
160 m_defaultNamespaceURI = attr->value();
161 else if (attr->prefix() == "xmlns")
162 namespaces.append(QXmlStreamNamespaceDeclaration(attr->localName(), attr->value()));
163 }
164 }
165 }
166 m_stream.addExtraNamespaceDeclarations(namespaces);
167 m_stream.setEntityResolver(new EntityResolver);
168
169 // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace.
170 if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument())
171 m_defaultNamespaceURI = parentElement->namespaceURI();
172 }
173
~XMLDocumentParser()174 XMLDocumentParser::~XMLDocumentParser()
175 {
176 clearCurrentNodeStack();
177 if (m_pendingScript)
178 m_pendingScript->removeClient(this);
179 delete m_stream.entityResolver();
180 }
181
doWrite(const String & parseString)182 void XMLDocumentParser::doWrite(const String& parseString)
183 {
184 m_wroteText = true;
185
186 if (document()->decoder() && document()->decoder()->sawError()) {
187 // If the decoder saw an error, report it as fatal (stops parsing)
188 handleError(fatal, "Encoding error", lineNumber(), columnNumber());
189 return;
190 }
191
192 QString data(parseString);
193 if (!data.isEmpty()) {
194 // JavaScript may cause the parser to detach,
195 // keep this alive until this function is done.
196 RefPtr<XMLDocumentParser> protect(this);
197
198 m_stream.addData(data);
199 parse();
200 }
201
202 return;
203 }
204
initializeParserContext(const CString &)205 void XMLDocumentParser::initializeParserContext(const CString&)
206 {
207 DocumentParser::startParsing();
208 m_sawError = false;
209 m_sawCSS = false;
210 m_sawXSLTransform = false;
211 m_sawFirstElement = false;
212 }
213
doEnd()214 void XMLDocumentParser::doEnd()
215 {
216 #if ENABLE(XSLT)
217 if (m_sawXSLTransform) {
218 document()->setTransformSource(adoptPtr(new TransformSource(m_originalSourceForTransform)));
219 document()->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
220 document()->styleSelectorChanged(RecalcStyleImmediately);
221 document()->setParsing(true);
222 DocumentParser::stopParsing();
223 }
224 #endif
225
226 if (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError
227 || (m_wroteText && !m_sawFirstElement && !m_sawXSLTransform && !m_sawError))
228 handleError(fatal, qPrintable(m_stream.errorString()), lineNumber(), columnNumber());
229 }
230
lineNumber() const231 int XMLDocumentParser::lineNumber() const
232 {
233 return m_stream.lineNumber();
234 }
235
columnNumber() const236 int XMLDocumentParser::columnNumber() const
237 {
238 return m_stream.columnNumber();
239 }
240
textPosition() const241 TextPosition0 XMLDocumentParser::textPosition() const
242 {
243 return TextPosition0(WTF::ZeroBasedNumber::fromZeroBasedInt(lineNumber()), WTF::ZeroBasedNumber::fromZeroBasedInt(columnNumber()));
244 }
245
246 // This method incorrectly reinterprets zero-base lineNumber method as one-based number.
247 // FIXME: This error is kept for compatibility. We should fix it eventually.
textPositionOneBased() const248 TextPosition1 XMLDocumentParser::textPositionOneBased() const
249 {
250 return TextPosition1(WTF::OneBasedNumber::fromOneBasedInt(lineNumber()), WTF::OneBasedNumber::fromOneBasedInt(columnNumber()));
251 }
252
stopParsing()253 void XMLDocumentParser::stopParsing()
254 {
255 ScriptableDocumentParser::stopParsing();
256 }
257
resumeParsing()258 void XMLDocumentParser::resumeParsing()
259 {
260 ASSERT(m_parserPaused);
261
262 m_parserPaused = false;
263
264 // First, execute any pending callbacks
265 parse();
266 if (m_parserPaused)
267 return;
268
269 // Then, write any pending data
270 SegmentedString rest = m_pendingSrc;
271 m_pendingSrc.clear();
272 append(rest);
273
274 // Finally, if finish() has been called and append() didn't result
275 // in any further callbacks being queued, call end()
276 if (m_finishCalled && !m_parserPaused && !m_pendingScript)
277 end();
278 }
279
appendFragmentSource(const String & source)280 bool XMLDocumentParser::appendFragmentSource(const String& source)
281 {
282 ASSERT(!m_sawFirstElement);
283 append(String("<qxmlstreamdummyelement>"));
284 append(source);
285 append(String("</qxmlstreamdummyelement>"));
286 return !hasError();
287 }
288
289 // --------------------------------
290
291 struct AttributeParseState {
292 HashMap<String, String> attributes;
293 bool gotAttributes;
294 };
295
attributesStartElementNsHandler(AttributeParseState * state,const QXmlStreamAttributes & attrs)296 static void attributesStartElementNsHandler(AttributeParseState* state, const QXmlStreamAttributes& attrs)
297 {
298 if (attrs.count() <= 0)
299 return;
300
301 state->gotAttributes = true;
302
303 for (int i = 0; i < attrs.count(); i++) {
304 const QXmlStreamAttribute& attr = attrs[i];
305 String attrLocalName = attr.name();
306 String attrValue = attr.value();
307 String attrURI = attr.namespaceUri();
308 String attrQName = attr.qualifiedName();
309 state->attributes.set(attrQName, attrValue);
310 }
311 }
312
parseAttributes(const String & string,bool & attrsOK)313 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
314 {
315 AttributeParseState state;
316 state.gotAttributes = false;
317
318 QXmlStreamReader stream;
319 QString dummy = QString(QLatin1String("<?xml version=\"1.0\"?><attrs %1 />")).arg(string);
320 stream.addData(dummy);
321 while (!stream.atEnd()) {
322 stream.readNext();
323 if (stream.isStartElement()) {
324 attributesStartElementNsHandler(&state, stream.attributes());
325 }
326 }
327 attrsOK = state.gotAttributes;
328 return state.attributes;
329 }
330
prefixFromQName(const QString & qName)331 static inline String prefixFromQName(const QString& qName)
332 {
333 const int offset = qName.indexOf(QLatin1Char(':'));
334 if (offset <= 0)
335 return String();
336 else
337 return qName.left(offset);
338 }
339
handleElementNamespaces(Element * newElement,const QXmlStreamNamespaceDeclarations & ns,ExceptionCode & ec,FragmentScriptingPermission scriptingPermission)340 static inline void handleElementNamespaces(Element* newElement, const QXmlStreamNamespaceDeclarations &ns,
341 ExceptionCode& ec, FragmentScriptingPermission scriptingPermission)
342 {
343 for (int i = 0; i < ns.count(); ++i) {
344 const QXmlStreamNamespaceDeclaration &decl = ns[i];
345 String namespaceURI = decl.namespaceUri();
346 String namespaceQName = decl.prefix().isEmpty() ? String("xmlns") : String("xmlns:");
347 namespaceQName.append(decl.prefix());
348 newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec, scriptingPermission);
349 if (ec) // exception setting attributes
350 return;
351 }
352 }
353
handleElementAttributes(Element * newElement,const QXmlStreamAttributes & attrs,ExceptionCode & ec,FragmentScriptingPermission scriptingPermission)354 static inline void handleElementAttributes(Element* newElement, const QXmlStreamAttributes &attrs, ExceptionCode& ec,
355 FragmentScriptingPermission scriptingPermission)
356 {
357 for (int i = 0; i < attrs.count(); ++i) {
358 const QXmlStreamAttribute &attr = attrs[i];
359 String attrLocalName = attr.name();
360 String attrValue = attr.value();
361 String attrURI = attr.namespaceUri().isEmpty() ? String() : String(attr.namespaceUri());
362 String attrQName = attr.qualifiedName();
363 newElement->setAttributeNS(attrURI, attrQName, attrValue, ec, scriptingPermission);
364 if (ec) // exception setting attributes
365 return;
366 }
367 }
368
parse()369 void XMLDocumentParser::parse()
370 {
371 while (!isStopped() && !m_parserPaused && !m_stream.atEnd()) {
372 m_stream.readNext();
373 switch (m_stream.tokenType()) {
374 case QXmlStreamReader::StartDocument: {
375 startDocument();
376 }
377 break;
378 case QXmlStreamReader::EndDocument: {
379 endDocument();
380 }
381 break;
382 case QXmlStreamReader::StartElement: {
383 #if ENABLE(XHTMLMP)
384 if (document()->isXHTMLMPDocument() && !m_hasDocTypeDeclaration) {
385 handleError(fatal, "DOCTYPE declaration lost.", lineNumber(), columnNumber());
386 break;
387 }
388 #endif
389 parseStartElement();
390 }
391 break;
392 case QXmlStreamReader::EndElement: {
393 parseEndElement();
394 }
395 break;
396 case QXmlStreamReader::Characters: {
397 if (m_stream.isCDATA()) {
398 //cdata
399 parseCdata();
400 } else {
401 //characters
402 parseCharacters();
403 }
404 }
405 break;
406 case QXmlStreamReader::Comment: {
407 parseComment();
408 }
409 break;
410 case QXmlStreamReader::DTD: {
411 //qDebug()<<"------------- DTD";
412 parseDtd();
413 #if ENABLE(XHTMLMP)
414 m_hasDocTypeDeclaration = true;
415 #endif
416 }
417 break;
418 case QXmlStreamReader::EntityReference: {
419 //qDebug()<<"---------- ENTITY = "<<m_stream.name().toString()
420 // <<", t = "<<m_stream.text().toString();
421 if (isXHTMLDocument()
422 #if ENABLE(XHTMLMP)
423 || isXHTMLMPDocument()
424 #endif
425 ) {
426 QString entity = m_stream.name().toString();
427 UChar c = decodeNamedEntity(entity.toUtf8().constData());
428 if (!m_currentNode->isTextNode())
429 enterText();
430 ExceptionCode ec = 0;
431 String str(&c, 1);
432 // qDebug()<<" ------- adding entity "<<str;
433 static_cast<Text*>(m_currentNode)->appendData(str, ec);
434 }
435 }
436 break;
437 case QXmlStreamReader::ProcessingInstruction: {
438 parseProcessingInstruction();
439 }
440 break;
441 default: {
442 if (m_stream.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
443 ErrorType type = (m_stream.error() == QXmlStreamReader::NotWellFormedError) ?
444 fatal : warning;
445 handleError(type, qPrintable(m_stream.errorString()), lineNumber(),
446 columnNumber());
447 }
448 }
449 break;
450 }
451 }
452 }
453
startDocument()454 void XMLDocumentParser::startDocument()
455 {
456 initializeParserContext();
457 ExceptionCode ec = 0;
458
459 if (!m_parsingFragment) {
460 document()->setXMLStandalone(m_stream.isStandaloneDocument(), ec);
461
462 QStringRef version = m_stream.documentVersion();
463 if (!version.isEmpty())
464 document()->setXMLVersion(version, ec);
465 QStringRef encoding = m_stream.documentEncoding();
466 if (!encoding.isEmpty())
467 document()->setXMLEncoding(encoding);
468 }
469 }
470
parseStartElement()471 void XMLDocumentParser::parseStartElement()
472 {
473 if (!m_sawFirstElement && m_parsingFragment) {
474 // skip dummy element for fragments
475 m_sawFirstElement = true;
476 return;
477 }
478
479 exitText();
480
481 String localName = m_stream.name();
482 String uri = m_stream.namespaceUri();
483 String prefix = prefixFromQName(m_stream.qualifiedName().toString());
484
485 if (m_parsingFragment && uri.isNull()) {
486 Q_ASSERT(prefix.isNull());
487 uri = m_defaultNamespaceURI;
488 }
489
490 QualifiedName qName(prefix, localName, uri);
491 RefPtr<Element> newElement = document()->createElement(qName, true);
492 if (!newElement) {
493 stopParsing();
494 return;
495 }
496
497 #if ENABLE(XHTMLMP)
498 if (!m_sawFirstElement && isXHTMLMPDocument()) {
499 // As per 7.1 section of OMA-WAP-XHTMLMP-V1_1-20061020-A.pdf,
500 // we should make sure that the root element MUST be 'html' and
501 // ensure the name of the default namespace on the root elment 'html'
502 // MUST be 'http://www.w3.org/1999/xhtml'
503 if (localName != HTMLNames::htmlTag.localName()) {
504 handleError(fatal, "XHTMLMP document expects 'html' as root element.", lineNumber(), columnNumber());
505 return;
506 }
507
508 if (uri.isNull()) {
509 m_defaultNamespaceURI = HTMLNames::xhtmlNamespaceURI;
510 uri = m_defaultNamespaceURI;
511 m_stream.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration(prefix, HTMLNames::xhtmlNamespaceURI));
512 }
513 }
514 #endif
515
516 bool isFirstElement = !m_sawFirstElement;
517 m_sawFirstElement = true;
518
519 ExceptionCode ec = 0;
520 handleElementNamespaces(newElement.get(), m_stream.namespaceDeclarations(), ec, m_scriptingPermission);
521 if (ec) {
522 stopParsing();
523 return;
524 }
525
526 handleElementAttributes(newElement.get(), m_stream.attributes(), ec, m_scriptingPermission);
527 if (ec) {
528 stopParsing();
529 return;
530 }
531
532 ScriptElement* scriptElement = toScriptElement(newElement.get());
533 if (scriptElement)
534 m_scriptStartPosition = textPositionOneBased();
535
536 m_currentNode->deprecatedParserAddChild(newElement.get());
537
538 pushCurrentNode(newElement.get());
539 if (m_view && !newElement->attached())
540 newElement->attach();
541
542 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
543 if (newElement->hasTagName(HTMLNames::htmlTag))
544 static_cast<HTMLHtmlElement*>(newElement.get())->insertedByParser();
545 #endif
546
547 if (isFirstElement && document()->frame())
548 document()->frame()->loader()->dispatchDocumentElementAvailable();
549 }
550
parseEndElement()551 void XMLDocumentParser::parseEndElement()
552 {
553 exitText();
554
555 RefPtr<Node> n = m_currentNode;
556 n->finishParsingChildren();
557
558 if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n.get()))) {
559 popCurrentNode();
560 ExceptionCode ec;
561 n->remove(ec);
562 return;
563 }
564
565 if (!n->isElementNode() || !m_view) {
566 if (!m_currentNodeStack.isEmpty())
567 popCurrentNode();
568 return;
569 }
570
571 Element* element = static_cast<Element*>(n.get());
572
573 // The element's parent may have already been removed from document.
574 // Parsing continues in this case, but scripts aren't executed.
575 if (!element->inDocument()) {
576 popCurrentNode();
577 return;
578 }
579
580 ScriptElement* scriptElement = toScriptElement(element);
581 if (!scriptElement) {
582 popCurrentNode();
583 return;
584 }
585
586 // don't load external scripts for standalone documents (for now)
587 ASSERT(!m_pendingScript);
588 m_requestingScript = true;
589
590 bool successfullyPrepared = scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute);
591 if (!successfullyPrepared) {
592 #if ENABLE(XHTMLMP)
593 if (!scriptElement->isScriptTypeSupported(ScriptElement::AllowLegacyTypeInTypeAttribute))
594 document()->setShouldProcessNoscriptElement(true);
595 #endif
596 } else {
597 if (scriptElement->readyToBeParserExecuted())
598 scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));
599 else if (scriptElement->willBeParserExecuted()) {
600 m_pendingScript = scriptElement->cachedScript();
601 m_scriptElement = element;
602 m_pendingScript->addClient(this);
603
604 // m_pendingScript will be 0 if script was already loaded and addClient() executed it.
605 if (m_pendingScript)
606 pauseParsing();
607 } else
608 m_scriptElement = 0;
609 }
610 m_requestingScript = false;
611 popCurrentNode();
612 }
613
parseCharacters()614 void XMLDocumentParser::parseCharacters()
615 {
616 if (!m_currentNode->isTextNode())
617 enterText();
618 ExceptionCode ec = 0;
619 static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
620 }
621
parseProcessingInstruction()622 void XMLDocumentParser::parseProcessingInstruction()
623 {
624 exitText();
625
626 // ### handle exceptions
627 int exception = 0;
628 RefPtr<ProcessingInstruction> pi = document()->createProcessingInstruction(
629 m_stream.processingInstructionTarget(),
630 m_stream.processingInstructionData(), exception);
631 if (exception)
632 return;
633
634 pi->setCreatedByParser(true);
635
636 m_currentNode->deprecatedParserAddChild(pi.get());
637 if (m_view && !pi->attached())
638 pi->attach();
639
640 pi->finishParsingChildren();
641
642 if (pi->isCSS())
643 m_sawCSS = true;
644 #if ENABLE(XSLT)
645 m_sawXSLTransform = !m_sawFirstElement && pi->isXSL();
646 if (m_sawXSLTransform && !document()->transformSourceDocument())
647 stopParsing();
648 #endif
649 }
650
parseCdata()651 void XMLDocumentParser::parseCdata()
652 {
653 exitText();
654
655 RefPtr<Node> newNode = CDATASection::create(document(), m_stream.text());
656
657 m_currentNode->deprecatedParserAddChild(newNode.get());
658 if (m_view && !newNode->attached())
659 newNode->attach();
660 }
661
parseComment()662 void XMLDocumentParser::parseComment()
663 {
664 exitText();
665
666 RefPtr<Node> newNode = Comment::create(document(), m_stream.text());
667
668 m_currentNode->deprecatedParserAddChild(newNode.get());
669 if (m_view && !newNode->attached())
670 newNode->attach();
671 }
672
endDocument()673 void XMLDocumentParser::endDocument()
674 {
675 #if ENABLE(XHTMLMP)
676 m_hasDocTypeDeclaration = false;
677 #endif
678 }
679
hasError() const680 bool XMLDocumentParser::hasError() const
681 {
682 return m_stream.hasError();
683 }
684
parseDtd()685 void XMLDocumentParser::parseDtd()
686 {
687 QStringRef name = m_stream.dtdName();
688 QStringRef publicId = m_stream.dtdPublicId();
689 QStringRef systemId = m_stream.dtdSystemId();
690
691 //qDebug() << dtd << name << publicId << systemId;
692 if ((publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Transitional//EN"))
693 || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1//EN"))
694 || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Strict//EN"))
695 || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Frameset//EN"))
696 || (publicId == QLatin1String("-//W3C//DTD XHTML Basic 1.0//EN"))
697 || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"))
698 || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"))
699 #if !ENABLE(XHTMLMP)
700 || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
701 #endif
702 )
703 setIsXHTMLDocument(true); // controls if we replace entities or not.
704 #if ENABLE(XHTMLMP)
705 else if ((publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.1//EN"))
706 || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))) {
707 if (AtomicString(name) != HTMLNames::htmlTag.localName()) {
708 handleError(fatal, "Invalid DOCTYPE declaration, expected 'html' as root element.", lineNumber(), columnNumber());
709 return;
710 }
711
712 if (document()->isXHTMLMPDocument()) // check if the MIME type is correct with this method
713 setIsXHTMLMPDocument(true);
714 else
715 setIsXHTMLDocument(true);
716 }
717 #endif
718 if (!m_parsingFragment)
719 document()->parserAddChild(DocumentType::create(document(), name, publicId, systemId));
720
721 }
722 }
723