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