diff options
Diffstat (limited to 'Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp')
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp | 425 |
1 files changed, 193 insertions, 232 deletions
diff --git a/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp b/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp index 1c1c61911..3d7f0e37e 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp +++ b/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Peter Kelly <pmk@post.com> - * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005-2017 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) @@ -29,40 +29,29 @@ #include "XMLDocumentParser.h" #include "CDATASection.h" -#include "CachedScript.h" #include "Comment.h" #include "CachedResourceLoader.h" #include "Document.h" #include "DocumentFragment.h" #include "DocumentType.h" -#include "ExceptionCodePlaceholder.h" #include "Frame.h" -#include "FrameLoader.h" -#include "FrameView.h" #include "HTMLEntityParser.h" #include "HTMLHtmlElement.h" -#include "HTMLLinkElement.h" -#include "HTMLNames.h" -#include "HTMLStyleElement.h" #include "HTMLTemplateElement.h" -#include "Page.h" +#include "InlineClassicScript.h" +#include "PendingScript.h" #include "ProcessingInstruction.h" #include "ResourceError.h" -#include "ResourceRequest.h" #include "ResourceResponse.h" #include "ScriptElement.h" #include "ScriptSourceCode.h" -#include "SecurityOrigin.h" #include "Settings.h" -#include "TextResourceDecoder.h" +#include "StyleScope.h" #include "TransformSource.h" #include "XMLNSNames.h" #include "XMLDocumentParserScope.h" #include <libxml/parserInternals.h> -#include <wtf/Ref.h> #include <wtf/StringExtras.h> -#include <wtf/Threading.h> -#include <wtf/Vector.h> #include <wtf/unicode/UTF8.h> #if ENABLE(XSLT) @@ -72,48 +61,49 @@ namespace WebCore { -static inline bool hasNoStyleInformation(Document* document) +#if ENABLE(XSLT) + +static inline bool shouldRenderInXMLTreeViewerMode(Document& document) { - if (document->sawElementsInKnownNamespaces()) + if (document.sawElementsInKnownNamespaces()) return false; -#if ENABLE(XSLT) - if (document->transformSourceDocument()) + + if (document.transformSourceDocument()) return false; -#endif - if (!document->frame() || !document->frame()->page()) + + auto* frame = document.frame(); + if (!frame) return false; - if (!document->frame()->page()->settings().developerExtrasEnabled()) + if (!frame->settings().developerExtrasEnabled()) return false; - if (document->frame()->tree().parent()) + if (frame->tree().parent()) return false; // This document is not in a top frame return true; } +#endif + class PendingCallbacks { - WTF_MAKE_NONCOPYABLE(PendingCallbacks); WTF_MAKE_FAST_ALLOCATED; + WTF_MAKE_FAST_ALLOCATED; public: - PendingCallbacks() { } - ~PendingCallbacks() { } - - void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, - const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** attributes) + void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int numNamespaces, const xmlChar** namespaces, int numAttributes, int numDefaulted, const xmlChar** attributes) { auto callback = std::make_unique<PendingStartElementNSCallback>(); callback->xmlLocalName = xmlStrdup(xmlLocalName); callback->xmlPrefix = xmlStrdup(xmlPrefix); callback->xmlURI = xmlStrdup(xmlURI); - callback->nb_namespaces = nb_namespaces; - callback->namespaces = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_namespaces * 2)); - for (int i = 0; i < nb_namespaces * 2 ; i++) + callback->numNamespaces = numNamespaces; + callback->namespaces = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * numNamespaces * 2)); + for (int i = 0; i < numNamespaces * 2 ; i++) callback->namespaces[i] = xmlStrdup(namespaces[i]); - callback->nb_attributes = nb_attributes; - callback->nb_defaulted = nb_defaulted; - callback->attributes = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_attributes * 5)); - for (int i = 0; i < nb_attributes; i++) { + callback->numAttributes = numAttributes; + callback->numDefaulted = numDefaulted; + callback->attributes = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * numAttributes * 5)); + for (int i = 0; i < numAttributes; i++) { // Each attribute has 5 elements in the array: // name, prefix, uri, value and an end pointer. @@ -126,7 +116,7 @@ public: callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len; } - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendEndElementNSCallback() @@ -141,7 +131,7 @@ public: callback->s = xmlStrndup(s, len); callback->len = len; - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendProcessingInstructionCallback(const xmlChar* target, const xmlChar* data) @@ -151,7 +141,7 @@ public: callback->target = xmlStrdup(target); callback->data = xmlStrdup(data); - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendCDATABlockCallback(const xmlChar* s, int len) @@ -161,7 +151,7 @@ public: callback->s = xmlStrndup(s, len); callback->len = len; - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendCommentCallback(const xmlChar* s) @@ -170,7 +160,7 @@ public: callback->s = xmlStrdup(s); - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendInternalSubsetCallback(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID) @@ -181,7 +171,7 @@ public: callback->externalID = xmlStrdup(externalID); callback->systemID = xmlStrdup(systemID); - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void appendErrorCallback(XMLErrors::ErrorType type, const xmlChar* message, OrdinalNumber lineNumber, OrdinalNumber columnNumber) @@ -193,7 +183,7 @@ public: callback->lineNumber = lineNumber; callback->columnNumber = columnNumber; - m_callbacks.append(std::move(callback)); + m_callbacks.append(WTFMove(callback)); } void callAndRemoveFirstCallback(XMLDocumentParser* parser) @@ -216,34 +206,33 @@ private: xmlFree(xmlLocalName); xmlFree(xmlPrefix); xmlFree(xmlURI); - for (int i = 0; i < nb_namespaces * 2; i++) + for (int i = 0; i < numNamespaces * 2; i++) xmlFree(namespaces[i]); xmlFree(namespaces); - for (int i = 0; i < nb_attributes; i++) + for (int i = 0; i < numAttributes; i++) { for (int j = 0; j < 4; j++) xmlFree(attributes[i * 5 + j]); + } xmlFree(attributes); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { - parser->startElementNs(xmlLocalName, xmlPrefix, xmlURI, - nb_namespaces, const_cast<const xmlChar**>(namespaces), - nb_attributes, nb_defaulted, const_cast<const xmlChar**>(attributes)); + parser->startElementNs(xmlLocalName, xmlPrefix, xmlURI, numNamespaces, const_cast<const xmlChar**>(namespaces), numAttributes, numDefaulted, const_cast<const xmlChar**>(attributes)); } xmlChar* xmlLocalName; xmlChar* xmlPrefix; xmlChar* xmlURI; - int nb_namespaces; + int numNamespaces; xmlChar** namespaces; - int nb_attributes; - int nb_defaulted; + int numAttributes; + int numDefaulted; xmlChar** attributes; }; struct PendingEndElementNSCallback : public PendingCallback { - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->endElementNs(); } @@ -255,7 +244,7 @@ private: xmlFree(s); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->characters(s, len); } @@ -271,7 +260,7 @@ private: xmlFree(data); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->processingInstruction(target, data); } @@ -286,7 +275,7 @@ private: xmlFree(s); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->cdataBlock(s, len); } @@ -301,7 +290,7 @@ private: xmlFree(s); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->comment(s); } @@ -317,7 +306,7 @@ private: xmlFree(systemID); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->internalSubset(name, externalID, systemID); } @@ -333,7 +322,7 @@ private: xmlFree(message); } - virtual void call(XMLDocumentParser* parser) + void call(XMLDocumentParser* parser) override { parser->handleError(type, reinterpret_cast<char*>(message), TextPosition(lineNumber, columnNumber)); } @@ -361,7 +350,11 @@ static int matchFunc(const char*) class OffsetBuffer { WTF_MAKE_FAST_ALLOCATED; public: - OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { } + OffsetBuffer(Vector<char> buffer) + : m_buffer(WTFMove(buffer)) + , m_currentOffset(0) + { + } int readOutBytes(char* outputBuffer, unsigned askedToRead) { @@ -428,7 +421,7 @@ static bool shouldAllowExternalLoad(const URL& url) // retrieved content. If we had more context, we could potentially allow // the parser to load a DTD. As things stand, we take the conservative // route and allow same-origin requests only. - if (!XMLDocumentParserScope::currentCachedResourceLoader->document()->securityOrigin()->canRequest(url)) { + if (!XMLDocumentParserScope::currentCachedResourceLoader->document()->securityOrigin().canRequest(url)) { XMLDocumentParserScope::currentCachedResourceLoader->printAccessDeniedMessage(url); return false; } @@ -448,24 +441,26 @@ static void* openFunc(const char* uri) ResourceError error; ResourceResponse response; - Vector<char> data; + RefPtr<SharedBuffer> data; { CachedResourceLoader* cachedResourceLoader = XMLDocumentParserScope::currentCachedResourceLoader; - XMLDocumentParserScope scope(0); + XMLDocumentParserScope scope(nullptr); // FIXME: We should restore the original global error handler as well. if (cachedResourceLoader->frame()) - cachedResourceLoader->frame()->loader().loadResourceSynchronously(url, AllowStoredCredentials, DoNotAskClientForCrossOriginCredentials, error, response, data); + cachedResourceLoader->frame()->loader().loadResourceSynchronously(url, AllowStoredCredentials, ClientCredentialPolicy::MayAskClientForCredentials, error, response, data); } // We have to check the URL again after the load to catch redirects. // See <https://bugs.webkit.org/show_bug.cgi?id=21963>. if (!shouldAllowExternalLoad(response.url())) return &globalDescriptor; - - return new OffsetBuffer(data); + Vector<char> buffer; + if (data) + buffer.append(data->data(), data->size()); + return new OffsetBuffer(WTFMove(buffer)); } static int readFunc(void* context, char* buffer, int len) @@ -502,7 +497,7 @@ static void errorFunc(void*, const char*, ...) static bool didInit = false; -PassRefPtr<XMLParserContext> XMLParserContext::createStringParser(xmlSAXHandlerPtr handlers, void* userData) +Ref<XMLParserContext> XMLParserContext::createStringParser(xmlSAXHandlerPtr handlers, void* userData) { if (!didInit) { xmlInitParser(); @@ -516,16 +511,16 @@ PassRefPtr<XMLParserContext> XMLParserContext::createStringParser(xmlSAXHandlerP parser->_private = userData; // Substitute entities. - xmlCtxtUseOptions(parser, XML_PARSE_NOENT); + xmlCtxtUseOptions(parser, XML_PARSE_NOENT | XML_PARSE_HUGE); switchToUTF16(parser); - return adoptRef(new XMLParserContext(parser)); + return adoptRef(*new XMLParserContext(parser)); } // Chunk should be encoded in UTF-8 -PassRefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerPtr handlers, void* userData, const CString& chunk) +RefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerPtr handlers, void* userData, const CString& chunk) { if (!didInit) { xmlInitParser(); @@ -545,7 +540,7 @@ PassRefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerP // Substitute entities. // FIXME: Why is XML_PARSE_NODICT needed? This is different from what createStringParser does. - xmlCtxtUseOptions(parser, XML_PARSE_NODICT | XML_PARSE_NOENT); + xmlCtxtUseOptions(parser, XML_PARSE_NODICT | XML_PARSE_NOENT | XML_PARSE_HUGE); // Internal initialization parser->sax2 = 1; @@ -556,7 +551,7 @@ PassRefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerP parser->str_xml_ns = xmlDictLookup(parser->dict, XML_XML_NAMESPACE, 36); parser->_private = userData; - return adoptRef(new XMLParserContext(parser)); + return adoptRef(*new XMLParserContext(parser)); } // -------------------------------- @@ -569,42 +564,16 @@ bool XMLDocumentParser::supportsXMLVersion(const String& version) XMLDocumentParser::XMLDocumentParser(Document& document, FrameView* frameView) : ScriptableDocumentParser(document) , m_view(frameView) - , m_context(0) , m_pendingCallbacks(std::make_unique<PendingCallbacks>()) - , m_depthTriggeringEntityExpansion(-1) - , m_isParsingEntityDeclaration(false) , m_currentNode(&document) - , m_sawError(false) - , m_sawCSS(false) - , m_sawXSLTransform(false) - , m_sawFirstElement(false) - , m_isXHTMLDocument(false) - , m_parserPaused(false) - , m_requestingScript(false) - , m_finishCalled(false) - , m_pendingScript(0) , m_scriptStartPosition(TextPosition::belowRangePosition()) - , m_parsingFragment(false) { } XMLDocumentParser::XMLDocumentParser(DocumentFragment& fragment, Element* parentElement, ParserContentPolicy parserContentPolicy) : ScriptableDocumentParser(fragment.document(), parserContentPolicy) - , m_view(0) - , m_context(0) , m_pendingCallbacks(std::make_unique<PendingCallbacks>()) - , m_depthTriggeringEntityExpansion(-1) - , m_isParsingEntityDeclaration(false) , m_currentNode(&fragment) - , m_sawError(false) - , m_sawCSS(false) - , m_sawXSLTransform(false) - , m_sawFirstElement(false) - , m_isXHTMLDocument(false) - , m_parserPaused(false) - , m_requestingScript(false) - , m_finishCalled(false) - , m_pendingScript(0) , m_scriptStartPosition(TextPosition::belowRangePosition()) , m_parsingFragment(true) { @@ -615,10 +584,10 @@ XMLDocumentParser::XMLDocumentParser(DocumentFragment& fragment, Element* parent while (parentElement) { elemStack.append(parentElement); - ContainerNode* n = parentElement->parentNode(); - if (!n || !n->isElementNode()) + ContainerNode* node = parentElement->parentNode(); + if (!is<Element>(node)) break; - parentElement = toElement(n); + parentElement = downcast<Element>(node); } if (elemStack.isEmpty()) @@ -656,7 +625,7 @@ XMLDocumentParser::~XMLDocumentParser() // FIXME: m_pendingScript handling should be moved into XMLDocumentParser.cpp! if (m_pendingScript) - m_pendingScript->removeClient(this); + m_pendingScript->clearClient(); } void XMLDocumentParser::doWrite(const String& parseString) @@ -672,11 +641,13 @@ void XMLDocumentParser::doWrite(const String& parseString) if (parseString.length()) { // JavaScript may cause the parser to detach during xmlParseChunk // keep this alive until this function is done. - Ref<XMLDocumentParser> protect(*this); + Ref<XMLDocumentParser> protectedThis(*this); + XMLDocumentParserScope scope(&document()->cachedResourceLoader()); + + // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16? switchToUTF16(context->context()); - XMLDocumentParserScope scope(document()->cachedResourceLoader()); - xmlParseChunk(context->context(), reinterpret_cast<const char*>(parseString.deprecatedCharacters()), sizeof(UChar) * parseString.length(), 0); + xmlParseChunk(context->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), sizeof(UChar) * parseString.length(), 0); // JavaScript (which may be run under the xmlParseChunk callstack) may // cause the parser to be stopped or detached. @@ -718,21 +689,22 @@ struct _xmlSAX2Namespace { }; typedef struct _xmlSAX2Namespace xmlSAX2Namespace; -static inline void handleNamespaceAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlNamespaces, int nb_namespaces, ExceptionCode& ec) +static inline bool handleNamespaceAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlNamespaces, int numNamespaces) { xmlSAX2Namespace* namespaces = reinterpret_cast<xmlSAX2Namespace*>(libxmlNamespaces); - for (int i = 0; i < nb_namespaces; i++) { + for (int i = 0; i < numNamespaces; i++) { AtomicString namespaceQName = xmlnsAtom; AtomicString namespaceURI = toAtomicString(namespaces[i].uri); if (namespaces[i].prefix) namespaceQName = "xmlns:" + toString(namespaces[i].prefix); - QualifiedName parsedName = anyName; - if (!Element::parseAttributeName(parsedName, XMLNSNames::xmlnsNamespaceURI, namespaceQName, ec)) - return; - - prefixedAttributes.append(Attribute(parsedName, namespaceURI)); + auto result = Element::parseAttributeName(XMLNSNames::xmlnsNamespaceURI, namespaceQName); + if (result.hasException()) + return false; + + prefixedAttributes.append(Attribute(result.releaseReturnValue(), namespaceURI)); } + return true; } struct _xmlSAX2Attributes { @@ -744,22 +716,23 @@ struct _xmlSAX2Attributes { }; typedef struct _xmlSAX2Attributes xmlSAX2Attributes; -static inline void handleElementAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlAttributes, int nb_attributes, ExceptionCode& ec) +static inline bool handleElementAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlAttributes, int numAttributes) { xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes); - for (int i = 0; i < nb_attributes; i++) { + for (int i = 0; i < numAttributes; i++) { int valueLength = static_cast<int>(attributes[i].end - attributes[i].value); AtomicString attrValue = toAtomicString(attributes[i].value, valueLength); String attrPrefix = toString(attributes[i].prefix); - AtomicString attrURI = attrPrefix.isEmpty() ? AtomicString() : toAtomicString(attributes[i].uri); + AtomicString attrURI = attrPrefix.isEmpty() ? nullAtom : toAtomicString(attributes[i].uri); AtomicString attrQName = attrPrefix.isEmpty() ? toAtomicString(attributes[i].localname) : attrPrefix + ":" + toString(attributes[i].localname); - QualifiedName parsedName = anyName; - if (!Element::parseAttributeName(parsedName, attrURI, attrQName, ec)) - return; + auto result = Element::parseAttributeName(attrURI, attrQName); + if (result.hasException()) + return false; - prefixedAttributes.append(Attribute(parsedName, attrValue)); + prefixedAttributes.append(Attribute(result.releaseReturnValue(), attrValue)); } + return true; } // This is a hack around https://bugzilla.gnome.org/show_bug.cgi?id=502960 @@ -775,19 +748,18 @@ static inline bool hackAroundLibXMLEntityParsingBug() #endif } -void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, - const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes) +void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int numNamespaces, const xmlChar** libxmlNamespaces, int numAttributes, int numDefaulted, const xmlChar** libxmlAttributes) { if (isStopped()) return; if (m_parserPaused) { - m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, - nb_attributes, nb_defaulted, libxmlAttributes); + m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, numNamespaces, libxmlNamespaces, numAttributes, numDefaulted, libxmlAttributes); return; } - exitText(); + if (!updateLeafTextNode()) + return; AtomicString localName = toAtomicString(xmlLocalName); AtomicString uri = toAtomicString(xmlURI); @@ -809,49 +781,38 @@ void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlCha m_sawFirstElement = true; QualifiedName qName(prefix, localName, uri); - RefPtr<Element> newElement = m_currentNode->document().createElement(qName, true); - if (!newElement) { - stopParsing(); - return; - } + auto newElement = m_currentNode->document().createElement(qName, true); Vector<Attribute> prefixedAttributes; - ExceptionCode ec = 0; - handleNamespaceAttributes(prefixedAttributes, libxmlNamespaces, nb_namespaces, ec); - if (ec) { - setAttributes(newElement.get(), prefixedAttributes, parserContentPolicy()); + if (!handleNamespaceAttributes(prefixedAttributes, libxmlNamespaces, numNamespaces)) { + setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy()); stopParsing(); return; } - handleElementAttributes(prefixedAttributes, libxmlAttributes, nb_attributes, ec); - setAttributes(newElement.get(), prefixedAttributes, parserContentPolicy()); - if (ec) { + bool success = handleElementAttributes(prefixedAttributes, libxmlAttributes, numAttributes); + setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy()); + if (!success) { stopParsing(); return; } newElement->beginParsingChildren(); - ScriptElement* scriptElement = toScriptElementIfPossible(newElement.get()); - if (scriptElement) + if (isScriptElement(newElement.get())) m_scriptStartPosition = textPosition(); - m_currentNode->parserAppendChild(newElement.get()); + m_currentNode->parserAppendChild(newElement); if (!m_currentNode) // Synchronous DOM events may have removed the current node. return; -#if ENABLE(TEMPLATE_ELEMENT) - if (newElement->hasTagName(HTMLNames::templateTag)) - pushCurrentNode(toHTMLTemplateElement(newElement.get())->content()); + if (is<HTMLTemplateElement>(newElement)) + pushCurrentNode(&downcast<HTMLTemplateElement>(newElement.get()).content()); else - pushCurrentNode(newElement.get()); -#else - pushCurrentNode(newElement.get()); -#endif + pushCurrentNode(newElement.ptr()); - if (newElement->hasTagName(HTMLNames::htmlTag)) - toHTMLHtmlElement(newElement.get())->insertedByParser(); + if (is<HTMLHtmlElement>(newElement)) + downcast<HTMLHtmlElement>(newElement.get()).insertedByParser(); if (!m_parsingFragment && isFirstElement && document()->frame()) document()->frame()->injectUserScripts(InjectAtDocumentStart); @@ -869,39 +830,39 @@ void XMLDocumentParser::endElementNs() // JavaScript can detach the parser. Make sure this is not released // before the end of this method. - Ref<XMLDocumentParser> protect(*this); + Ref<XMLDocumentParser> protectedThis(*this); - exitText(); + if (!updateLeafTextNode()) + return; - RefPtr<ContainerNode> n = m_currentNode; - n->finishParsingChildren(); + RefPtr<ContainerNode> node = m_currentNode; + node->finishParsingChildren(); // Once we reach the depth again where entity expansion started, stop executing the work-around. if (hackAroundLibXMLEntityParsingBug() && context()->depth <= depthTriggeringEntityExpansion()) setDepthTriggeringEntityExpansion(-1); - if (!scriptingContentIsAllowed(parserContentPolicy()) && n->isElementNode() && toScriptElementIfPossible(toElement(n.get()))) { + if (!scriptingContentIsAllowed(parserContentPolicy()) && is<Element>(*node) && isScriptElement(downcast<Element>(*node))) { popCurrentNode(); - n->remove(IGNORE_EXCEPTION); + node->remove(); return; } - if (!n->isElementNode() || !m_view) { + if (!node->isElementNode() || !m_view) { popCurrentNode(); return; } - Element* element = toElement(n.get()); + auto& element = downcast<Element>(*node); // The element's parent may have already been removed from document. // Parsing continues in this case, but scripts aren't executed. - if (!element->inDocument()) { + if (!element.isConnected()) { popCurrentNode(); return; } - ScriptElement* scriptElement = toScriptElementIfPossible(element); - if (!scriptElement) { + if (!isScriptElement(element)) { popCurrentNode(); return; } @@ -910,22 +871,21 @@ void XMLDocumentParser::endElementNs() ASSERT(!m_pendingScript); m_requestingScript = true; - if (scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute)) { + auto& scriptElement = downcastScriptElement(element); + if (scriptElement.prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute)) { // FIXME: Script execution should be shared between // the libxml2 and Qt XMLDocumentParser implementations. - if (scriptElement->readyToBeParserExecuted()) - scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition)); - else if (scriptElement->willBeParserExecuted()) { - m_pendingScript = scriptElement->cachedScript(); - m_scriptElement = element; - m_pendingScript->addClient(this); + if (scriptElement.readyToBeParserExecuted()) + scriptElement.executeClassicScript(ScriptSourceCode(scriptElement.scriptContent(), document()->url(), m_scriptStartPosition, JSC::SourceProviderSourceType::Program, InlineClassicScript::create(scriptElement))); + else if (scriptElement.willBeParserExecuted() && scriptElement.loadableScript()) { + m_pendingScript = PendingScript::create(scriptElement, *scriptElement.loadableScript()); + m_pendingScript->setClient(*this); - // m_pendingScript will be 0 if script was already loaded and addClient() executed it. + // m_pendingScript will be nullptr if script was already loaded and setClient() executed it. if (m_pendingScript) pauseParsing(); - } else - m_scriptElement = 0; + } // JavaScript may have detached the parser if (isDetached()) @@ -935,19 +895,19 @@ void XMLDocumentParser::endElementNs() popCurrentNode(); } -void XMLDocumentParser::characters(const xmlChar* s, int len) +void XMLDocumentParser::characters(const xmlChar* characters, int length) { if (isStopped()) return; if (m_parserPaused) { - m_pendingCallbacks->appendCharactersCallback(s, len); + m_pendingCallbacks->appendCharactersCallback(characters, length); return; } if (!m_leafTextNode) - enterText(); - m_bufferedText.append(s, len); + createLeafTextNode(); + m_bufferedText.append(characters, length); } void XMLDocumentParser::error(XMLErrors::ErrorType type, const char* message, va_list args) @@ -955,24 +915,19 @@ void XMLDocumentParser::error(XMLErrors::ErrorType type, const char* message, va if (isStopped()) return; -#if HAVE(VASPRINTF) - char* m; - if (vasprintf(&m, message, args) == -1) - return; -#else - char m[1024]; - vsnprintf(m, sizeof(m) - 1, message, args); -#endif + va_list preflightArgs; + va_copy(preflightArgs, args); + size_t stringLength = vsnprintf(nullptr, 0, message, preflightArgs); + va_end(preflightArgs); + + Vector<char, 1024> buffer(stringLength + 1); + vsnprintf(buffer.data(), stringLength + 1, message, args); TextPosition position = textPosition(); if (m_parserPaused) - m_pendingCallbacks->appendErrorCallback(type, reinterpret_cast<const xmlChar*>(m), position.m_line, position.m_column); + m_pendingCallbacks->appendErrorCallback(type, reinterpret_cast<const xmlChar*>(buffer.data()), position.m_line, position.m_column); else - handleError(type, m, textPosition()); - -#if HAVE(VASPRINTF) - free(m); -#endif + handleError(type, buffer.data(), textPosition()); } void XMLDocumentParser::processingInstruction(const xmlChar* target, const xmlChar* data) @@ -985,23 +940,23 @@ void XMLDocumentParser::processingInstruction(const xmlChar* target, const xmlCh return; } - exitText(); + if (!updateLeafTextNode()) + return; - // ### handle exceptions - ExceptionCode ec = 0; - RefPtr<ProcessingInstruction> pi = m_currentNode->document().createProcessingInstruction( - toString(target), toString(data), ec); - if (ec) + auto result = m_currentNode->document().createProcessingInstruction(toString(target), toString(data)); + if (result.hasException()) return; + auto pi = result.releaseReturnValue(); pi->setCreatedByParser(true); - m_currentNode->parserAppendChild(pi.get()); + m_currentNode->parserAppendChild(pi); pi->finishParsingChildren(); if (pi->isCSS()) m_sawCSS = true; + #if ENABLE(XSLT) m_sawXSLTransform = !m_sawFirstElement && pi->isXSL(); if (m_sawXSLTransform && !document()->transformSourceDocument()) @@ -1019,10 +974,10 @@ void XMLDocumentParser::cdataBlock(const xmlChar* s, int len) return; } - exitText(); + if (!updateLeafTextNode()) + return; - RefPtr<CDATASection> newNode = CDATASection::create(m_currentNode->document(), toString(s, len)); - m_currentNode->parserAppendChild(newNode.release()); + m_currentNode->parserAppendChild(CDATASection::create(m_currentNode->document(), toString(s, len))); } void XMLDocumentParser::comment(const xmlChar* s) @@ -1035,10 +990,10 @@ void XMLDocumentParser::comment(const xmlChar* s) return; } - exitText(); + if (!updateLeafTextNode()) + return; - RefPtr<Comment> newNode = Comment::create(m_currentNode->document(), toString(s)); - m_currentNode->parserAppendChild(newNode.release()); + m_currentNode->parserAppendChild(Comment::create(m_currentNode->document(), toString(s))); } enum StandaloneInfo { @@ -1057,9 +1012,9 @@ void XMLDocumentParser::startDocument(const xmlChar* version, const xmlChar* enc } if (version) - document()->setXMLVersion(toString(version), ASSERT_NO_EXCEPTION); + document()->setXMLVersion(toString(version)); if (standalone != StandaloneUnspecified) - document()->setXMLStandalone(standaloneInfo == StandaloneYes, ASSERT_NO_EXCEPTION); + document()->setXMLStandalone(standaloneInfo == StandaloneYes); if (encoding) document()->setXMLEncoding(toString(encoding)); document()->setHasXMLDeclaration(true); @@ -1067,7 +1022,7 @@ void XMLDocumentParser::startDocument(const xmlChar* version, const xmlChar* enc void XMLDocumentParser::endDocument() { - exitText(); + updateLeafTextNode(); } void XMLDocumentParser::internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID) @@ -1095,21 +1050,20 @@ static inline XMLDocumentParser* getParser(void* closure) static inline bool hackAroundLibXMLEntityBug(void* closure) { #if LIBXML_VERSION >= 20627 - UNUSED_PARAM(closure); - // This bug has been fixed in libxml 2.6.27. + UNUSED_PARAM(closure); return false; #else return static_cast<xmlParserCtxtPtr>(closure)->node; #endif } -static void startElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes) +static void startElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri, int numNamespaces, const xmlChar** namespaces, int numAttributes, int numDefaulted, const xmlChar** libxmlAttributes) { if (hackAroundLibXMLEntityBug(closure)) return; - getParser(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes); + getParser(closure)->startElementNs(localname, prefix, uri, numNamespaces, namespaces, numAttributes, numDefaulted, libxmlAttributes); } static void endElementNsHandler(void* closure, const xmlChar*, const xmlChar*, const xmlChar*) @@ -1199,13 +1153,12 @@ static xmlEntityPtr sharedXHTMLEntity() static size_t convertUTF16EntityToUTF8(const UChar* utf16Entity, size_t numberOfCodeUnits, char* target, size_t targetSize) { const char* originalTarget = target; - WTF::Unicode::ConversionResult conversionResult = WTF::Unicode::convertUTF16ToUTF8(&utf16Entity, - utf16Entity + numberOfCodeUnits, &target, target + targetSize); + auto conversionResult = WTF::Unicode::convertUTF16ToUTF8(&utf16Entity, utf16Entity + numberOfCodeUnits, &target, target + targetSize); if (conversionResult != WTF::Unicode::conversionOK) return 0; // Even though we must pass the length, libxml expects the entity string to be null terminated. - ASSERT(target > originalTarget + 1); + ASSERT(target >= originalTarget + 1); *target = '\0'; return target - originalTarget; } @@ -1303,6 +1256,7 @@ static void externalSubsetHandler(void* closure, const xmlChar*, const xmlChar* || (extId == "-//W3C//DTD XHTML Basic 1.0//EN") || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN") || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN") + || (extId == "-//W3C//DTD MathML 2.0//EN") || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN") || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.1//EN") || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.2//EN")) @@ -1344,7 +1298,7 @@ void XMLDocumentParser::initializeParserContext(const CString& chunk) m_sawXSLTransform = false; m_sawFirstElement = false; - XMLDocumentParserScope scope(document()->cachedResourceLoader()); + XMLDocumentParserScope scope(&document()->cachedResourceLoader()); if (m_parsingFragment) m_context = XMLParserContext::createMemoryParser(&sax, this, chunk); else { @@ -1359,25 +1313,25 @@ void XMLDocumentParser::doEnd() if (m_context) { // Tell libxml we're done. { - XMLDocumentParserScope scope(document()->cachedResourceLoader()); + XMLDocumentParserScope scope(&document()->cachedResourceLoader()); xmlParseChunk(context(), 0, 0, 1); } - m_context = 0; + m_context = nullptr; } } #if ENABLE(XSLT) - bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && hasNoStyleInformation(document()); + bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && shouldRenderInXMLTreeViewerMode(*document()); if (xmlViewerMode) { XMLTreeViewer xmlTreeViewer(*document()); xmlTreeViewer.transformDocumentToTreeView(); } else if (m_sawXSLTransform) { - void* doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform.toString(), document()->url().string()); - document()->setTransformSource(adoptPtr(new TransformSource(doc))); + xmlDocPtr doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform.toString(), document()->url().string()); + document()->setTransformSource(std::make_unique<TransformSource>(doc)); document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets. - document()->styleResolverChanged(RecalcStyleImmediately); + document()->styleScope().didChangeActiveStyleSheetCandidates(); // styleResolverChanged() call can detach the parser and null out its document. // In that case, we just bail out. @@ -1398,10 +1352,10 @@ static inline const char* nativeEndianUTF16Encoding() return BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE"; } -void* xmlDocPtrForString(CachedResourceLoader* cachedResourceLoader, const String& source, const String& url) +xmlDocPtr xmlDocPtrForString(CachedResourceLoader& cachedResourceLoader, const String& source, const String& url) { if (source.isEmpty()) - return 0; + return nullptr; // Parse in a single chunk into an xmlDocPtr // FIXME: Hook up error handlers so that a failure to parse the main document results in @@ -1412,7 +1366,7 @@ void* xmlDocPtrForString(CachedResourceLoader* cachedResourceLoader, const Strin size_t sizeInBytes = source.length() * (is8Bit ? sizeof(LChar) : sizeof(UChar)); const char* encoding = is8Bit ? "iso-8859-1" : nativeEndianUTF16Encoding(); - XMLDocumentParserScope scope(cachedResourceLoader, errorFunc, 0); + XMLDocumentParserScope scope(&cachedResourceLoader, errorFunc); return xmlReadMemory(characters, sizeInBytes, url.latin1().data(), encoding, XSLT_PARSE_OPTIONS); } #endif @@ -1421,11 +1375,16 @@ TextPosition XMLDocumentParser::textPosition() const { xmlParserCtxtPtr context = this->context(); if (!context) - return TextPosition::minimumPosition(); + return TextPosition(); return TextPosition(OrdinalNumber::fromOneBasedInt(context->input->line), OrdinalNumber::fromOneBasedInt(context->input->col)); } +bool XMLDocumentParser::shouldAssociateConsoleMessagesWithTextPosition() const +{ + return !m_parserPaused && !m_requestingScript; +} + void XMLDocumentParser::stopParsing() { DocumentParser::stopParsing(); @@ -1449,13 +1408,12 @@ void XMLDocumentParser::resumeParsing() return; } - // Then, write any pending data - SegmentedString rest = m_pendingSrc; - m_pendingSrc.clear(); // There is normally only one string left, so toString() shouldn't copy. // In any case, the XML parser runs on the main thread and it's OK if // the passed string has more than one reference. - append(rest.toString().impl()); + auto rest = m_pendingSrc.toString(); + m_pendingSrc.clear(); + append(rest.impl()); // Finally, if finish() has been called and write() didn't result // in any further callbacks being queued, call end() @@ -1500,9 +1458,7 @@ struct AttributeParseState { bool gotAttributes; }; -static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLocalName, const xmlChar* /*xmlPrefix*/, - const xmlChar* /*xmlURI*/, int /*nb_namespaces*/, const xmlChar** /*namespaces*/, - int nb_attributes, int /*nb_defaulted*/, const xmlChar** libxmlAttributes) +static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLocalName, const xmlChar* /*xmlPrefix*/, const xmlChar* /*xmlURI*/, int /*numNamespaces*/, const xmlChar** /*namespaces*/, int numAttributes, int /*numDefaulted*/, const xmlChar** libxmlAttributes) { if (strcmp(reinterpret_cast<const char*>(xmlLocalName), "attrs") != 0) return; @@ -1513,7 +1469,7 @@ static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLoc state->gotAttributes = true; xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes); - for (int i = 0; i < nb_attributes; i++) { + for (int i = 0; i < numAttributes; i++) { String attrLocalName = toString(attributes[i].localname); int valueLength = (int) (attributes[i].end - attributes[i].value); String attrValue = toString(attributes[i].value, valueLength); @@ -1526,6 +1482,8 @@ static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLoc HashMap<String, String> parseAttributes(const String& string, bool& attrsOK) { + String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />"; + AttributeParseState state; state.gotAttributes = false; @@ -1533,11 +1491,14 @@ HashMap<String, String> parseAttributes(const String& string, bool& attrsOK) memset(&sax, 0, sizeof(sax)); sax.startElementNs = attributesStartElementNsHandler; sax.initialized = XML_SAX2_MAGIC; + RefPtr<XMLParserContext> parser = XMLParserContext::createStringParser(&sax, &state); - String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />"; - xmlParseChunk(parser->context(), reinterpret_cast<const char*>(parseString.deprecatedCharacters()), parseString.length() * sizeof(UChar), 1); + + // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16? + xmlParseChunk(parser->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), parseString.length() * sizeof(UChar), 1); + attrsOK = state.gotAttributes; - return state.attributes; + return WTFMove(state.attributes); } } |