diff options
Diffstat (limited to 'Source/WebCore/xml/parser')
-rw-r--r-- | Source/WebCore/xml/parser/CharacterReferenceParserInlines.h | 164 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/MarkupTokenizerInlines.h | 107 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParser.cpp | 109 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParser.h | 232 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp | 425 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParserScope.cpp | 2 | ||||
-rw-r--r-- | Source/WebCore/xml/parser/XMLDocumentParserScope.h | 9 |
7 files changed, 487 insertions, 561 deletions
diff --git a/Source/WebCore/xml/parser/CharacterReferenceParserInlines.h b/Source/WebCore/xml/parser/CharacterReferenceParserInlines.h index 62780c7dc..76862683f 100644 --- a/Source/WebCore/xml/parser/CharacterReferenceParserInlines.h +++ b/Source/WebCore/xml/parser/CharacterReferenceParserInlines.h @@ -24,27 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CharacterReferenceParserInlines_h -#define CharacterReferenceParserInlines_h +#pragma once #include <wtf/text/StringBuilder.h> namespace WebCore { -inline bool isHexDigit(UChar cc) +inline void unconsumeCharacters(SegmentedString& source, StringBuilder& consumedCharacters) { - return (cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'f') || (cc >= 'A' && cc <= 'F'); -} - -inline void unconsumeCharacters(SegmentedString& source, const StringBuilder& consumedCharacters) -{ - if (consumedCharacters.length() == 1) - source.push(consumedCharacters[0]); - else if (consumedCharacters.length() == 2) { - source.push(consumedCharacters[0]); - source.push(consumedCharacters[1]); - } else - source.prepend(SegmentedString(consumedCharacters.toStringPreserveCapacity())); + source.pushBack(consumedCharacters.toString()); } template <typename ParserFunctions> @@ -54,7 +42,7 @@ bool consumeCharacterReference(SegmentedString& source, StringBuilder& decodedCh ASSERT(!notEnoughCharacters); ASSERT(decodedCharacter.isEmpty()); - enum EntityState { + enum { Initial, Number, MaybeHexLowerCaseX, @@ -62,105 +50,101 @@ bool consumeCharacterReference(SegmentedString& source, StringBuilder& decodedCh Hex, Decimal, Named - }; - EntityState entityState = Initial; + } state = Initial; UChar32 result = 0; + bool overflow = false; StringBuilder consumedCharacters; while (!source.isEmpty()) { - UChar cc = source.currentChar(); - switch (entityState) { - case Initial: { - if (cc == '\x09' || cc == '\x0A' || cc == '\x0C' || cc == ' ' || cc == '<' || cc == '&') + UChar character = source.currentCharacter(); + switch (state) { + case Initial: + if (character == '\x09' || character == '\x0A' || character == '\x0C' || character == ' ' || character == '<' || character == '&') return false; - if (additionalAllowedCharacter && cc == additionalAllowedCharacter) + if (additionalAllowedCharacter && character == additionalAllowedCharacter) return false; - if (cc == '#') { - entityState = Number; + if (character == '#') { + state = Number; break; } - if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) { - entityState = Named; - continue; + if (isASCIIAlpha(character)) { + state = Named; + goto Named; } return false; - } - case Number: { - if (cc == 'x') { - entityState = MaybeHexLowerCaseX; + case Number: + if (character == 'x') { + state = MaybeHexLowerCaseX; break; } - if (cc == 'X') { - entityState = MaybeHexUpperCaseX; + if (character == 'X') { + state = MaybeHexUpperCaseX; break; } - if (cc >= '0' && cc <= '9') { - entityState = Decimal; - continue; + if (isASCIIDigit(character)) { + state = Decimal; + goto Decimal; } - source.push('#'); + source.pushBack(ASCIILiteral("#")); return false; - } - case MaybeHexLowerCaseX: { - if (isHexDigit(cc)) { - entityState = Hex; - continue; + case MaybeHexLowerCaseX: + if (isASCIIHexDigit(character)) { + state = Hex; + goto Hex; } - source.push('#'); - source.push('x'); + source.pushBack(ASCIILiteral("#x")); return false; - } - case MaybeHexUpperCaseX: { - if (isHexDigit(cc)) { - entityState = Hex; - continue; + case MaybeHexUpperCaseX: + if (isASCIIHexDigit(character)) { + state = Hex; + goto Hex; } - source.push('#'); - source.push('X'); + source.pushBack(ASCIILiteral("#X")); return false; - } - case Hex: { - if (cc >= '0' && cc <= '9') - result = result * 16 + cc - '0'; - else if (cc >= 'a' && cc <= 'f') - result = result * 16 + 10 + cc - 'a'; - else if (cc >= 'A' && cc <= 'F') - result = result * 16 + 10 + cc - 'A'; - else if (cc == ';') { - source.advanceAndASSERT(cc); - decodedCharacter.append(ParserFunctions::legalEntityFor(result)); + case Hex: + Hex: + if (isASCIIHexDigit(character)) { + result = result * 16 + toASCIIHexValue(character); + if (result > UCHAR_MAX_VALUE) + overflow = true; + break; + } + if (character == ';') { + source.advancePastNonNewline(); + decodedCharacter.append(ParserFunctions::legalEntityFor(overflow ? 0 : result)); return true; - } else if (ParserFunctions::acceptMalformed()) { - decodedCharacter.append(ParserFunctions::legalEntityFor(result)); + } + if (ParserFunctions::acceptMalformed()) { + decodedCharacter.append(ParserFunctions::legalEntityFor(overflow ? 0 : result)); return true; - } else { - unconsumeCharacters(source, consumedCharacters); - return false; } - break; - } - case Decimal: { - if (cc >= '0' && cc <= '9') - result = result * 10 + cc - '0'; - else if (cc == ';') { - source.advanceAndASSERT(cc); - decodedCharacter.append(ParserFunctions::legalEntityFor(result)); + unconsumeCharacters(source, consumedCharacters); + return false; + case Decimal: + Decimal: + if (isASCIIDigit(character)) { + result = result * 10 + character - '0'; + if (result > UCHAR_MAX_VALUE) + overflow = true; + break; + } + if (character == ';') { + source.advancePastNonNewline(); + decodedCharacter.append(ParserFunctions::legalEntityFor(overflow ? 0 : result)); return true; - } else if (ParserFunctions::acceptMalformed()) { - decodedCharacter.append(ParserFunctions::legalEntityFor(result)); + } + if (ParserFunctions::acceptMalformed()) { + decodedCharacter.append(ParserFunctions::legalEntityFor(overflow ? 0 : result)); return true; - } else { - unconsumeCharacters(source, consumedCharacters); - return false; } - break; - } - case Named: { - return ParserFunctions::consumeNamedEntity(source, decodedCharacter, notEnoughCharacters, additionalAllowedCharacter, cc); - } + unconsumeCharacters(source, consumedCharacters); + return false; + case Named: + Named: + return ParserFunctions::consumeNamedEntity(source, decodedCharacter, notEnoughCharacters, additionalAllowedCharacter, character); } - consumedCharacters.append(cc); - source.advanceAndASSERT(cc); + consumedCharacters.append(character); + source.advancePastNonNewline(); } ASSERT(source.isEmpty()); notEnoughCharacters = true; @@ -168,6 +152,4 @@ bool consumeCharacterReference(SegmentedString& source, StringBuilder& decodedCh return false; } -} - -#endif // CharacterReferenceParserInlines_h +} // namespace WebCore diff --git a/Source/WebCore/xml/parser/MarkupTokenizerInlines.h b/Source/WebCore/xml/parser/MarkupTokenizerInlines.h index e0b3156bb..58ef106ae 100644 --- a/Source/WebCore/xml/parser/MarkupTokenizerInlines.h +++ b/Source/WebCore/xml/parser/MarkupTokenizerInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2016 Apple Inc. All Rights Reserved. * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ * Copyright (C) 2010 Google, Inc. All Rights Reserved. * @@ -25,71 +25,72 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MarkupTokenizerInlines_h -#define MarkupTokenizerInlines_h +#pragma once -#include "SegmentedString.h" +#if COMPILER(MSVC) +// Disable the "unreachable code" warning so we can compile the ASSERT_NOT_REACHED in the END_STATE macro. +#pragma warning(disable: 4702) +#endif namespace WebCore { -inline bool isTokenizerWhitespace(UChar cc) +inline bool isTokenizerWhitespace(UChar character) { - return cc == ' ' || cc == '\x0A' || cc == '\x09' || cc == '\x0C'; + return character == ' ' || character == '\x0A' || character == '\x09' || character == '\x0C'; } -inline void advanceStringAndASSERTIgnoringCase(SegmentedString& source, const char* expectedCharacters) -{ - while (*expectedCharacters) - source.advanceAndASSERTIgnoringCase(*expectedCharacters++); -} +#define BEGIN_STATE(stateName) \ + case stateName: \ + stateName: { \ + constexpr auto currentState = stateName; \ + UNUSED_PARAM(currentState); -inline void advanceStringAndASSERT(SegmentedString& source, const char* expectedCharacters) -{ - while (*expectedCharacters) - source.advanceAndASSERT(*expectedCharacters++); -} +#define END_STATE() \ + ASSERT_NOT_REACHED(); \ + break; \ + } -#if COMPILER(MSVC) -// We need to disable the "unreachable code" warning because we want to assert -// that some code points aren't reached in the state machine. -#pragma warning(disable: 4702) -#endif - -#define BEGIN_STATE(prefix, stateName) case prefix::stateName: stateName: -#define END_STATE() ASSERT_NOT_REACHED(); break; - -// We use this macro when the HTML5 spec says "reconsume the current input -// character in the <mumble> state." -#define RECONSUME_IN(prefix, stateName) \ - do { \ - m_state = prefix::stateName; \ - goto stateName; \ +#define RETURN_IN_CURRENT_STATE(expression) \ + do { \ + m_state = currentState; \ + return expression; \ } while (false) -// We use this macro when the HTML5 spec says "consume the next input -// character ... and switch to the <mumble> state." -#define ADVANCE_TO(prefix, stateName) \ - do { \ - m_state = prefix::stateName; \ - if (!m_inputStreamPreprocessor.advance(source)) \ - return haveBufferedCharacterToken(); \ - cc = m_inputStreamPreprocessor.nextInputCharacter(); \ - goto stateName; \ +// We use this macro when the HTML spec says "reconsume the current input character in the <mumble> state." +#define RECONSUME_IN(newState) \ + do { \ + goto newState; \ } while (false) -// Sometimes there's more complicated logic in the spec that separates when -// we consume the next input character and when we switch to a particular -// state. We handle those cases by advancing the source directly and using -// this macro to switch to the indicated state. -#define SWITCH_TO(prefix, stateName) \ - do { \ - m_state = prefix::stateName; \ - if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source)) \ - return haveBufferedCharacterToken(); \ - cc = m_inputStreamPreprocessor.nextInputCharacter(); \ - goto stateName; \ +// We use this macro when the HTML spec says "consume the next input character ... and switch to the <mumble> state." +#define ADVANCE_TO(newState) \ + do { \ + if (!m_preprocessor.advance(source, isNullCharacterSkippingState(newState))) { \ + m_state = newState; \ + return haveBufferedCharacterToken(); \ + } \ + character = m_preprocessor.nextInputCharacter(); \ + goto newState; \ + } while (false) +#define ADVANCE_PAST_NON_NEWLINE_TO(newState) \ + do { \ + if (!m_preprocessor.advancePastNonNewline(source, isNullCharacterSkippingState(newState))) { \ + m_state = newState; \ + return haveBufferedCharacterToken(); \ + } \ + character = m_preprocessor.nextInputCharacter(); \ + goto newState; \ } while (false) -} +// For more complex cases, caller consumes the characters first and then uses this macro. +#define SWITCH_TO(newState) \ + do { \ + if (!m_preprocessor.peek(source, isNullCharacterSkippingState(newState))) { \ + m_state = newState; \ + return haveBufferedCharacterToken(); \ + } \ + character = m_preprocessor.nextInputCharacter(); \ + goto newState; \ + } while (false) -#endif // MarkupTokenizerInlines_h +} // namespace WebCore diff --git a/Source/WebCore/xml/parser/XMLDocumentParser.cpp b/Source/WebCore/xml/parser/XMLDocumentParser.cpp index 547ffcb05..4cbccd970 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParser.cpp +++ b/Source/WebCore/xml/parser/XMLDocumentParser.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) @@ -27,9 +27,7 @@ #include "XMLDocumentParser.h" #include "CDATASection.h" -#include "CachedScript.h" #include "Comment.h" -#include "CachedResourceLoader.h" #include "Document.h" #include "DocumentFragment.h" #include "DocumentType.h" @@ -40,12 +38,16 @@ #include "HTMLNames.h" #include "HTMLStyleElement.h" #include "ImageLoader.h" +#include "PendingScript.h" #include "ProcessingInstruction.h" #include "ResourceError.h" #include "ResourceRequest.h" #include "ResourceResponse.h" +#include "SVGNames.h" +#include "SVGStyleElement.h" #include "ScriptElement.h" #include "ScriptSourceCode.h" +#include "StyleScope.h" #include "TextResourceDecoder.h" #include "TreeDepthLimit.h" #include <wtf/Ref.h> @@ -53,11 +55,6 @@ #include <wtf/Threading.h> #include <wtf/Vector.h> -#if ENABLE(SVG) -#include "SVGNames.h" -#include "SVGStyleElement.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -91,8 +88,8 @@ void XMLDocumentParser::clearCurrentNodeStack() { if (m_currentNode && m_currentNode != document()) m_currentNode->deref(); - m_currentNode = 0; - m_leafTextNode = 0; + m_currentNode = nullptr; + m_leafTextNode = nullptr; if (m_currentNodeStack.size()) { // Aborted parsing. for (size_t i = m_currentNodeStack.size() - 1; i != 0; --i) @@ -103,14 +100,15 @@ void XMLDocumentParser::clearCurrentNodeStack() } } -void XMLDocumentParser::insert(const SegmentedString&) +void XMLDocumentParser::insert(SegmentedString&&) { ASSERT_NOT_REACHED(); } -void XMLDocumentParser::append(PassRefPtr<StringImpl> inputSource) +void XMLDocumentParser::append(RefPtr<StringImpl>&& inputSource) { - SegmentedString source(inputSource); + String source { WTFMove(inputSource) }; + if (m_sawXSLTransform || !m_sawFirstElement) m_originalSourceForTransform.append(source); @@ -122,16 +120,16 @@ void XMLDocumentParser::append(PassRefPtr<StringImpl> inputSource) return; } - doWrite(source.toString()); + doWrite(source); - // After parsing, go ahead and dispatch image beforeload events. + // After parsing, dispatch image beforeload events. ImageLoader::dispatchPendingBeforeLoadEvents(); } void XMLDocumentParser::handleError(XMLErrors::ErrorType type, const char* m, TextPosition position) { if (!m_xmlErrors) - m_xmlErrors = std::make_unique<XMLErrors>(document()); + m_xmlErrors = std::make_unique<XMLErrors>(*document()); m_xmlErrors->handleError(type, m, position); if (type != XMLErrors::warning) m_sawError = true; @@ -139,12 +137,15 @@ void XMLDocumentParser::handleError(XMLErrors::ErrorType type, const char* m, Te stopParsing(); } -void XMLDocumentParser::enterText() +void XMLDocumentParser::createLeafTextNode() { + if (m_leafTextNode) + return; + ASSERT(m_bufferedText.size() == 0); ASSERT(!m_leafTextNode); m_leafTextNode = Text::create(m_currentNode->document(), ""); - m_currentNode->parserAppendChild(m_leafTextNode.get()); + m_currentNode->parserAppendChild(*m_leafTextNode); } static inline String toString(const xmlChar* string, size_t size) @@ -152,20 +153,23 @@ static inline String toString(const xmlChar* string, size_t size) return String::fromUTF8(reinterpret_cast<const char*>(string), size); } - -void XMLDocumentParser::exitText() +bool XMLDocumentParser::updateLeafTextNode() { if (isStopped()) - return; + return false; if (!m_leafTextNode) - return; + return true; + + // This operation might fire mutation event, see below. + m_leafTextNode->appendData(toString(m_bufferedText.data(), m_bufferedText.size())); + m_bufferedText = { }; - m_leafTextNode->appendData(toString(m_bufferedText.data(), m_bufferedText.size()), IGNORE_EXCEPTION); - Vector<xmlChar> empty; - m_bufferedText.swap(empty); + m_leafTextNode = nullptr; - m_leafTextNode = 0; + // Hence, we need to check again whether the parser is stopped, since mutation + // event handlers executed by appendData might have detached this parser. + return !isStopped(); } void XMLDocumentParser::detach() @@ -191,11 +195,13 @@ void XMLDocumentParser::end() if (m_parserPaused) return; - if (m_sawError) + if (m_sawError) { insertErrorMessageBlock(); - else { - exitText(); - document()->styleResolverChanged(RecalcStyleImmediately); + if (isDetached()) // Inserting an error message may have ran arbitrary scripts. + return; + } else { + updateLeafTextNode(); + document()->styleScope().didChangeStyleSheetEnvironment(); } if (isParsing()) @@ -211,6 +217,8 @@ void XMLDocumentParser::finish() // makes sense to call any methods on DocumentParser once it's been stopped. // However, FrameLoader::stop calls DocumentParser::finish unconditionally. + Ref<XMLDocumentParser> protectedThis(*this); + if (m_parserPaused) m_finishCalled = true; else @@ -223,35 +231,17 @@ void XMLDocumentParser::insertErrorMessageBlock() m_xmlErrors->insertErrorMessageBlock(); } -void XMLDocumentParser::notifyFinished(CachedResource* unusedResource) +void XMLDocumentParser::notifyFinished(PendingScript& pendingScript) { - ASSERT_UNUSED(unusedResource, unusedResource == m_pendingScript); - ASSERT(m_pendingScript->accessCount() > 0); - - ScriptSourceCode sourceCode(m_pendingScript.get()); - bool errorOccurred = m_pendingScript->errorOccurred(); - bool wasCanceled = m_pendingScript->wasCanceled(); - - m_pendingScript->removeClient(this); - m_pendingScript = 0; - - RefPtr<Element> e = m_scriptElement; - m_scriptElement = 0; - - ScriptElement* scriptElement = toScriptElementIfPossible(e.get()); - ASSERT(scriptElement); + ASSERT(&pendingScript == m_pendingScript.get()); // JavaScript can detach this parser, make sure it's kept alive even if detached. - Ref<XMLDocumentParser> protect(*this); - - if (errorOccurred) - scriptElement->dispatchErrorEvent(); - else if (!wasCanceled) { - scriptElement->executeScript(sourceCode); - scriptElement->dispatchLoadEvent(); - } + Ref<XMLDocumentParser> protectedThis(*this); - m_scriptElement = 0; + m_pendingScript = nullptr; + pendingScript.clearClient(); + + pendingScript.element().executePendingScript(pendingScript); if (!isDetached() && !m_requestingScript) resumeParsing(); @@ -264,6 +254,8 @@ bool XMLDocumentParser::isWaitingForScripts() const void XMLDocumentParser::pauseParsing() { + ASSERT(!m_parserPaused); + if (m_parsingFragment) return; @@ -278,17 +270,16 @@ bool XMLDocumentParser::parseDocumentFragment(const String& chunk, DocumentFragm // FIXME: We need to implement the HTML5 XML Fragment parsing algorithm: // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#xml-fragment-parsing-algorithm // For now we have a hack for script/style innerHTML support: - if (contextElement && (contextElement->hasLocalName(HTMLNames::scriptTag) || contextElement->hasLocalName(HTMLNames::styleTag))) { + if (contextElement && (contextElement->hasLocalName(HTMLNames::scriptTag.localName()) || contextElement->hasLocalName(HTMLNames::styleTag.localName()))) { fragment.parserAppendChild(fragment.document().createTextNode(chunk)); return true; } RefPtr<XMLDocumentParser> parser = XMLDocumentParser::create(fragment, contextElement, parserContentPolicy); bool wellFormed = parser->appendFragmentSource(chunk); - // Do not call finish(). Current finish() and doEnd() implementations touch the main Document/loader - // and can cause crashes in the fragment case. + // Do not call finish(). The finish() and doEnd() implementations touch the main document and loader and can cause crashes in the fragment case. parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction. - return wellFormed; // appendFragmentSource()'s wellFormed is more permissive than wellFormed(). + return wellFormed; // appendFragmentSource()'s wellFormed is more permissive than Document::wellFormed(). } } // namespace WebCore diff --git a/Source/WebCore/xml/parser/XMLDocumentParser.h b/Source/WebCore/xml/parser/XMLDocumentParser.h index 7b7e22038..161fd5db8 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParser.h +++ b/Source/WebCore/xml/parser/XMLDocumentParser.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2000 Peter Kelly (pmk@post.com) - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005-2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) @@ -22,180 +22,174 @@ * */ -#ifndef XMLDocumentParser_h -#define XMLDocumentParser_h +#pragma once -#include "CachedResourceClient.h" -#include "CachedResourceHandle.h" #include "FragmentScriptingPermission.h" +#include "PendingScriptClient.h" #include "ScriptableDocumentParser.h" #include "SegmentedString.h" #include "XMLErrors.h" +#include <libxml/tree.h> +#include <libxml/xmlstring.h> #include <wtf/HashMap.h> #include <wtf/text/AtomicStringHash.h> #include <wtf/text/CString.h> -#include <libxml/tree.h> -#include <libxml/xmlstring.h> - namespace WebCore { class ContainerNode; -class CachedScript; class CachedResourceLoader; class DocumentFragment; -class Document; class Element; class FrameView; class PendingCallbacks; class Text; - class XMLParserContext : public RefCounted<XMLParserContext> { - public: - static PassRefPtr<XMLParserContext> createMemoryParser(xmlSAXHandlerPtr, void* userData, const CString& chunk); - static PassRefPtr<XMLParserContext> createStringParser(xmlSAXHandlerPtr, void* userData); - ~XMLParserContext(); - xmlParserCtxtPtr context() const { return m_context; } +class XMLParserContext : public RefCounted<XMLParserContext> { +public: + static RefPtr<XMLParserContext> createMemoryParser(xmlSAXHandlerPtr, void* userData, const CString& chunk); + static Ref<XMLParserContext> createStringParser(xmlSAXHandlerPtr, void* userData); + ~XMLParserContext(); + xmlParserCtxtPtr context() const { return m_context; } + +private: + XMLParserContext(xmlParserCtxtPtr context) + : m_context(context) + { + } + xmlParserCtxtPtr m_context; +}; + +class XMLDocumentParser final : public ScriptableDocumentParser, public PendingScriptClient { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref<XMLDocumentParser> create(Document& document, FrameView* view) + { + return adoptRef(*new XMLDocumentParser(document, view)); + } + static Ref<XMLDocumentParser> create(DocumentFragment& fragment, Element* element, ParserContentPolicy parserContentPolicy) + { + return adoptRef(*new XMLDocumentParser(fragment, element, parserContentPolicy)); + } - private: - XMLParserContext(xmlParserCtxtPtr context) - : m_context(context) - { - } - xmlParserCtxtPtr m_context; - }; + ~XMLDocumentParser(); - class XMLDocumentParser : public ScriptableDocumentParser, public CachedResourceClient { - WTF_MAKE_FAST_ALLOCATED; - public: - static PassRefPtr<XMLDocumentParser> create(Document& document, FrameView* view) - { - return adoptRef(new XMLDocumentParser(document, view)); - } - static PassRefPtr<XMLDocumentParser> create(DocumentFragment& fragment, Element* element, ParserContentPolicy parserContentPolicy) - { - return adoptRef(new XMLDocumentParser(fragment, element, parserContentPolicy)); - } + // Exposed for callbacks: + void handleError(XMLErrors::ErrorType, const char* message, TextPosition); - ~XMLDocumentParser(); + void setIsXHTMLDocument(bool isXHTML) { m_isXHTMLDocument = isXHTML; } + bool isXHTMLDocument() const { return m_isXHTMLDocument; } - // Exposed for callbacks: - void handleError(XMLErrors::ErrorType, const char* message, TextPosition); + static bool parseDocumentFragment(const String&, DocumentFragment&, Element* parent = nullptr, ParserContentPolicy = AllowScriptingContent); - void setIsXHTMLDocument(bool isXHTML) { m_isXHTMLDocument = isXHTML; } - bool isXHTMLDocument() const { return m_isXHTMLDocument; } + // Used by XMLHttpRequest to check if the responseXML was well formed. + bool wellFormed() const final { return !m_sawError; } - static bool parseDocumentFragment(const String&, DocumentFragment&, Element* parent = 0, ParserContentPolicy = AllowScriptingContent); + static bool supportsXMLVersion(const String&); - // Used by the XMLHttpRequest to check if the responseXML was well formed. - virtual bool wellFormed() const { return !m_sawError; } +private: + explicit XMLDocumentParser(Document&, FrameView* = nullptr); + XMLDocumentParser(DocumentFragment&, Element*, ParserContentPolicy); - TextPosition textPosition() const; + void insert(SegmentedString&&) final; + void append(RefPtr<StringImpl>&&) final; + void finish() final; + bool isWaitingForScripts() const final; + void stopParsing() final; + void detach() final; - static bool supportsXMLVersion(const String&); + TextPosition textPosition() const final; + bool shouldAssociateConsoleMessagesWithTextPosition() const final; - private: - XMLDocumentParser(Document&, FrameView* = 0); - XMLDocumentParser(DocumentFragment&, Element*, ParserContentPolicy); + void notifyFinished(PendingScript&) final; - // From DocumentParser - virtual void insert(const SegmentedString&); - virtual void append(PassRefPtr<StringImpl>); - virtual void finish(); - virtual bool isWaitingForScripts() const; - virtual void stopParsing(); - virtual void detach(); + void end(); - // from CachedResourceClient - virtual void notifyFinished(CachedResource*); + void pauseParsing(); + void resumeParsing(); - void end(); + bool appendFragmentSource(const String&); - void pauseParsing(); - void resumeParsing(); +public: + // Callbacks from parser SAX, and other functions needed inside + // the parser implementation, but outside this class. - bool appendFragmentSource(const String&); + void error(XMLErrors::ErrorType, const char* message, va_list args) WTF_ATTRIBUTE_PRINTF(3, 0); + void startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, + int numNamespaces, const xmlChar** namespaces, + int numAttributes, int numDefaulted, const xmlChar** libxmlAttributes); + void endElementNs(); + void characters(const xmlChar*, int length); + void processingInstruction(const xmlChar* target, const xmlChar* data); + void cdataBlock(const xmlChar*, int length); + void comment(const xmlChar*); + void startDocument(const xmlChar* version, const xmlChar* encoding, int standalone); + void internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID); + void endDocument(); -public: - // callbacks from parser SAX - void error(XMLErrors::ErrorType, const char* message, va_list args) WTF_ATTRIBUTE_PRINTF(3, 0); - void startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces, - const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes); - void endElementNs(); - void characters(const xmlChar* s, int len); - void processingInstruction(const xmlChar* target, const xmlChar* data); - void cdataBlock(const xmlChar* s, int len); - void comment(const xmlChar* s); - void startDocument(const xmlChar* version, const xmlChar* encoding, int standalone); - void internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID); - void endDocument(); + bool isParsingEntityDeclaration() const { return m_isParsingEntityDeclaration; } + void setIsParsingEntityDeclaration(bool value) { m_isParsingEntityDeclaration = value; } - bool isParsingEntityDeclaration() const { return m_isParsingEntityDeclaration; } - void setIsParsingEntityDeclaration(bool value) { m_isParsingEntityDeclaration = value; } + int depthTriggeringEntityExpansion() const { return m_depthTriggeringEntityExpansion; } + void setDepthTriggeringEntityExpansion(int depth) { m_depthTriggeringEntityExpansion = depth; } - int depthTriggeringEntityExpansion() const { return m_depthTriggeringEntityExpansion; } - void setDepthTriggeringEntityExpansion(int depth) { m_depthTriggeringEntityExpansion = depth; } +private: + void initializeParserContext(const CString& chunk = CString()); - private: - void initializeParserContext(const CString& chunk = CString()); + void pushCurrentNode(ContainerNode*); + void popCurrentNode(); + void clearCurrentNodeStack(); - void pushCurrentNode(ContainerNode*); - void popCurrentNode(); - void clearCurrentNodeStack(); + void insertErrorMessageBlock(); - void insertErrorMessageBlock(); + void createLeafTextNode(); + bool updateLeafTextNode(); - void enterText(); - void exitText(); + void doWrite(const String&); + void doEnd(); - void doWrite(const String&); - void doEnd(); + xmlParserCtxtPtr context() const { return m_context ? m_context->context() : nullptr; }; - FrameView* m_view; + FrameView* m_view { nullptr }; - SegmentedString m_originalSourceForTransform; + SegmentedString m_originalSourceForTransform; - xmlParserCtxtPtr context() const { return m_context ? m_context->context() : 0; }; - RefPtr<XMLParserContext> m_context; - std::unique_ptr<PendingCallbacks> m_pendingCallbacks; - Vector<xmlChar> m_bufferedText; - int m_depthTriggeringEntityExpansion; - bool m_isParsingEntityDeclaration; + RefPtr<XMLParserContext> m_context; + std::unique_ptr<PendingCallbacks> m_pendingCallbacks; + Vector<xmlChar> m_bufferedText; + int m_depthTriggeringEntityExpansion { -1 }; + bool m_isParsingEntityDeclaration { false }; - ContainerNode* m_currentNode; - Vector<ContainerNode*> m_currentNodeStack; + ContainerNode* m_currentNode { nullptr }; + Vector<ContainerNode*> m_currentNodeStack; - RefPtr<Text> m_leafTextNode; + RefPtr<Text> m_leafTextNode; - bool m_sawError; - bool m_sawCSS; - bool m_sawXSLTransform; - bool m_sawFirstElement; - bool m_isXHTMLDocument; - bool m_parserPaused; - bool m_requestingScript; - bool m_finishCalled; + bool m_sawError { false }; + bool m_sawCSS { false }; + bool m_sawXSLTransform { false }; + bool m_sawFirstElement { false }; + bool m_isXHTMLDocument { false }; + bool m_parserPaused { false }; + bool m_requestingScript { false }; + bool m_finishCalled { false }; - std::unique_ptr<XMLErrors> m_xmlErrors; + std::unique_ptr<XMLErrors> m_xmlErrors; - CachedResourceHandle<CachedScript> m_pendingScript; - RefPtr<Element> m_scriptElement; - TextPosition m_scriptStartPosition; + RefPtr<PendingScript> m_pendingScript; + TextPosition m_scriptStartPosition; - bool m_parsingFragment; - AtomicString m_defaultNamespaceURI; + bool m_parsingFragment { false }; + AtomicString m_defaultNamespaceURI; - typedef HashMap<AtomicString, AtomicString> PrefixForNamespaceMap; - PrefixForNamespaceMap m_prefixToNamespaceMap; - SegmentedString m_pendingSrc; - }; + HashMap<AtomicString, AtomicString> m_prefixToNamespaceMap; + SegmentedString m_pendingSrc; +}; #if ENABLE(XSLT) -void* xmlDocPtrForString(CachedResourceLoader*, const String& source, const String& url); +xmlDocPtr xmlDocPtrForString(CachedResourceLoader&, const String& source, const String& url); #endif HashMap<String, String> parseAttributes(const String&, bool& attrsOK); } // namespace WebCore - -#endif // XMLDocumentParser_h 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); } } diff --git a/Source/WebCore/xml/parser/XMLDocumentParserScope.cpp b/Source/WebCore/xml/parser/XMLDocumentParserScope.cpp index 0a473ed23..c0f3590bf 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParserScope.cpp +++ b/Source/WebCore/xml/parser/XMLDocumentParserScope.cpp @@ -28,7 +28,7 @@ namespace WebCore { -CachedResourceLoader* XMLDocumentParserScope::currentCachedResourceLoader = 0; +CachedResourceLoader* XMLDocumentParserScope::currentCachedResourceLoader = nullptr; XMLDocumentParserScope::XMLDocumentParserScope(CachedResourceLoader* cachedResourceLoader) : m_oldCachedResourceLoader(currentCachedResourceLoader) diff --git a/Source/WebCore/xml/parser/XMLDocumentParserScope.h b/Source/WebCore/xml/parser/XMLDocumentParserScope.h index c04043b48..828214d87 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParserScope.h +++ b/Source/WebCore/xml/parser/XMLDocumentParserScope.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef XMLDocumentParserScope_h -#define XMLDocumentParserScope_h +#pragma once #include <wtf/Noncopyable.h> @@ -39,13 +38,13 @@ namespace WebCore { class XMLDocumentParserScope { WTF_MAKE_NONCOPYABLE(XMLDocumentParserScope); public: - XMLDocumentParserScope(CachedResourceLoader* cachedResourceLoader); + explicit XMLDocumentParserScope(CachedResourceLoader*); ~XMLDocumentParserScope(); static CachedResourceLoader* currentCachedResourceLoader; #if ENABLE(XSLT) - XMLDocumentParserScope(CachedResourceLoader* cachedResourceLoader, xmlGenericErrorFunc genericErrorFunc, xmlStructuredErrorFunc structuredErrorFunc = 0, void* errorContext = 0); + XMLDocumentParserScope(CachedResourceLoader*, xmlGenericErrorFunc, xmlStructuredErrorFunc structuredErrorFunc = 0, void* errorContext = nullptr); #endif private: @@ -59,5 +58,3 @@ namespace WebCore { }; } // namespace WebCore - -#endif // XMLDocumentParserScope_h |