Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / xml / parser / XMLDocumentParserLibxml2.cpp
1 /*
2  * Copyright (C) 2000 Peter Kelly <pmk@post.com>
3  * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
4  * Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
5  * Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7  * Copyright (C) 2008 Holger Hans Peter Freyther
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
10  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "XMLDocumentParser.h"
30
31 #include "CDATASection.h"
32 #include "CachedScript.h"
33 #include "Comment.h"
34 #include "CachedResourceLoader.h"
35 #include "Document.h"
36 #include "DocumentFragment.h"
37 #include "DocumentType.h"
38 #include "ExceptionCodePlaceholder.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameView.h"
42 #include "HTMLEntityParser.h"
43 #include "HTMLHtmlElement.h"
44 #include "HTMLLinkElement.h"
45 #include "HTMLNames.h"
46 #include "HTMLStyleElement.h"
47 #include "HTMLTemplateElement.h"
48 #include "Page.h"
49 #include "ProcessingInstruction.h"
50 #include "ResourceError.h"
51 #include "ResourceRequest.h"
52 #include "ResourceResponse.h"
53 #include "ScriptElement.h"
54 #include "ScriptSourceCode.h"
55 #include "SecurityOrigin.h"
56 #include "Settings.h"
57 #include "TextResourceDecoder.h"
58 #include "TransformSource.h"
59 #include "XMLNSNames.h"
60 #include "XMLDocumentParserScope.h"
61 #include <libxml/parserInternals.h>
62 #include <wtf/Ref.h>
63 #include <wtf/StringExtras.h>
64 #include <wtf/Threading.h>
65 #include <wtf/Vector.h>
66 #include <wtf/unicode/UTF8.h>
67
68 #if ENABLE(XSLT)
69 #include "XMLTreeViewer.h"
70 #include <libxslt/xslt.h>
71 #endif
72
73 namespace WebCore {
74
75 #if ENABLE(XSLT)
76 static inline bool hasNoStyleInformation(Document* document)
77 {
78     if (document->sawElementsInKnownNamespaces())
79         return false;
80
81     if (document->transformSourceDocument())
82         return false;
83
84     if (!document->frame() || !document->frame()->page())
85         return false;
86
87     if (!document->frame()->page()->settings().developerExtrasEnabled())
88         return false;
89
90     if (document->frame()->tree().parent())
91         return false; // This document is not in a top frame
92
93     return true;
94 }
95 #endif
96
97 class PendingCallbacks {
98     WTF_MAKE_NONCOPYABLE(PendingCallbacks); WTF_MAKE_FAST_ALLOCATED;
99 public:
100     PendingCallbacks() { }
101     ~PendingCallbacks() { }
102
103     void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
104                                       const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** attributes)
105     {
106         auto callback = std::make_unique<PendingStartElementNSCallback>();
107
108         callback->xmlLocalName = xmlStrdup(xmlLocalName);
109         callback->xmlPrefix = xmlStrdup(xmlPrefix);
110         callback->xmlURI = xmlStrdup(xmlURI);
111         callback->nb_namespaces = nb_namespaces;
112         callback->namespaces = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_namespaces * 2));
113         for (int i = 0; i < nb_namespaces * 2 ; i++)
114             callback->namespaces[i] = xmlStrdup(namespaces[i]);
115         callback->nb_attributes = nb_attributes;
116         callback->nb_defaulted = nb_defaulted;
117         callback->attributes = static_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_attributes * 5));
118         for (int i = 0; i < nb_attributes; i++) {
119             // Each attribute has 5 elements in the array:
120             // name, prefix, uri, value and an end pointer.
121
122             for (int j = 0; j < 3; j++)
123                 callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]);
124
125             int len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
126
127             callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len);
128             callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len;
129         }
130
131         m_callbacks.append(WTFMove(callback));
132     }
133
134     void appendEndElementNSCallback()
135     {
136         m_callbacks.append(std::make_unique<PendingEndElementNSCallback>());
137     }
138
139     void appendCharactersCallback(const xmlChar* s, int len)
140     {
141         auto callback = std::make_unique<PendingCharactersCallback>();
142
143         callback->s = xmlStrndup(s, len);
144         callback->len = len;
145
146         m_callbacks.append(WTFMove(callback));
147     }
148
149     void appendProcessingInstructionCallback(const xmlChar* target, const xmlChar* data)
150     {
151         auto callback = std::make_unique<PendingProcessingInstructionCallback>();
152
153         callback->target = xmlStrdup(target);
154         callback->data = xmlStrdup(data);
155
156         m_callbacks.append(WTFMove(callback));
157     }
158
159     void appendCDATABlockCallback(const xmlChar* s, int len)
160     {
161         auto callback = std::make_unique<PendingCDATABlockCallback>();
162
163         callback->s = xmlStrndup(s, len);
164         callback->len = len;
165
166         m_callbacks.append(WTFMove(callback));
167     }
168
169     void appendCommentCallback(const xmlChar* s)
170     {
171         auto callback = std::make_unique<PendingCommentCallback>();
172
173         callback->s = xmlStrdup(s);
174
175         m_callbacks.append(WTFMove(callback));
176     }
177
178     void appendInternalSubsetCallback(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
179     {
180         auto callback = std::make_unique<PendingInternalSubsetCallback>();
181
182         callback->name = xmlStrdup(name);
183         callback->externalID = xmlStrdup(externalID);
184         callback->systemID = xmlStrdup(systemID);
185
186         m_callbacks.append(WTFMove(callback));
187     }
188
189     void appendErrorCallback(XMLErrors::ErrorType type, const xmlChar* message, OrdinalNumber lineNumber, OrdinalNumber columnNumber)
190     {
191         auto callback = std::make_unique<PendingErrorCallback>();
192
193         callback->message = xmlStrdup(message);
194         callback->type = type;
195         callback->lineNumber = lineNumber;
196         callback->columnNumber = columnNumber;
197
198         m_callbacks.append(WTFMove(callback));
199     }
200
201     void callAndRemoveFirstCallback(XMLDocumentParser* parser)
202     {
203         std::unique_ptr<PendingCallback> callback = m_callbacks.takeFirst();
204         callback->call(parser);
205     }
206
207     bool isEmpty() const { return m_callbacks.isEmpty(); }
208
209 private:
210     struct PendingCallback {
211         virtual ~PendingCallback() { }
212         virtual void call(XMLDocumentParser* parser) = 0;
213     };
214
215     struct PendingStartElementNSCallback : public PendingCallback {
216         virtual ~PendingStartElementNSCallback()
217         {
218             xmlFree(xmlLocalName);
219             xmlFree(xmlPrefix);
220             xmlFree(xmlURI);
221             for (int i = 0; i < nb_namespaces * 2; i++)
222                 xmlFree(namespaces[i]);
223             xmlFree(namespaces);
224             for (int i = 0; i < nb_attributes; i++)
225                 for (int j = 0; j < 4; j++)
226                     xmlFree(attributes[i * 5 + j]);
227             xmlFree(attributes);
228         }
229
230         virtual void call(XMLDocumentParser* parser)
231         {
232             parser->startElementNs(xmlLocalName, xmlPrefix, xmlURI,
233                                       nb_namespaces, const_cast<const xmlChar**>(namespaces),
234                                       nb_attributes, nb_defaulted, const_cast<const xmlChar**>(attributes));
235         }
236
237         xmlChar* xmlLocalName;
238         xmlChar* xmlPrefix;
239         xmlChar* xmlURI;
240         int nb_namespaces;
241         xmlChar** namespaces;
242         int nb_attributes;
243         int nb_defaulted;
244         xmlChar** attributes;
245     };
246
247     struct PendingEndElementNSCallback : public PendingCallback {
248         virtual void call(XMLDocumentParser* parser)
249         {
250             parser->endElementNs();
251         }
252     };
253
254     struct PendingCharactersCallback : public PendingCallback {
255         virtual ~PendingCharactersCallback()
256         {
257             xmlFree(s);
258         }
259
260         virtual void call(XMLDocumentParser* parser)
261         {
262             parser->characters(s, len);
263         }
264
265         xmlChar* s;
266         int len;
267     };
268
269     struct PendingProcessingInstructionCallback : public PendingCallback {
270         virtual ~PendingProcessingInstructionCallback()
271         {
272             xmlFree(target);
273             xmlFree(data);
274         }
275
276         virtual void call(XMLDocumentParser* parser)
277         {
278             parser->processingInstruction(target, data);
279         }
280
281         xmlChar* target;
282         xmlChar* data;
283     };
284
285     struct PendingCDATABlockCallback : public PendingCallback {
286         virtual ~PendingCDATABlockCallback()
287         {
288             xmlFree(s);
289         }
290
291         virtual void call(XMLDocumentParser* parser)
292         {
293             parser->cdataBlock(s, len);
294         }
295
296         xmlChar* s;
297         int len;
298     };
299
300     struct PendingCommentCallback : public PendingCallback {
301         virtual ~PendingCommentCallback()
302         {
303             xmlFree(s);
304         }
305
306         virtual void call(XMLDocumentParser* parser)
307         {
308             parser->comment(s);
309         }
310
311         xmlChar* s;
312     };
313
314     struct PendingInternalSubsetCallback : public PendingCallback {
315         virtual ~PendingInternalSubsetCallback()
316         {
317             xmlFree(name);
318             xmlFree(externalID);
319             xmlFree(systemID);
320         }
321
322         virtual void call(XMLDocumentParser* parser)
323         {
324             parser->internalSubset(name, externalID, systemID);
325         }
326
327         xmlChar* name;
328         xmlChar* externalID;
329         xmlChar* systemID;
330     };
331
332     struct PendingErrorCallback: public PendingCallback {
333         virtual ~PendingErrorCallback()
334         {
335             xmlFree(message);
336         }
337
338         virtual void call(XMLDocumentParser* parser)
339         {
340             parser->handleError(type, reinterpret_cast<char*>(message), TextPosition(lineNumber, columnNumber));
341         }
342
343         XMLErrors::ErrorType type;
344         xmlChar* message;
345         OrdinalNumber lineNumber;
346         OrdinalNumber columnNumber;
347     };
348
349     Deque<std::unique_ptr<PendingCallback>> m_callbacks;
350 };
351 // --------------------------------
352
353 static int globalDescriptor = 0;
354 static ThreadIdentifier libxmlLoaderThread = 0;
355
356 static int matchFunc(const char*)
357 {
358     // Only match loads initiated due to uses of libxml2 from within XMLDocumentParser to avoid
359     // interfering with client applications that also use libxml2.  http://bugs.webkit.org/show_bug.cgi?id=17353
360     return XMLDocumentParserScope::currentCachedResourceLoader && currentThread() == libxmlLoaderThread;
361 }
362
363 class OffsetBuffer {
364     WTF_MAKE_FAST_ALLOCATED;
365 public:
366     OffsetBuffer(Vector<char> buffer)
367         : m_buffer(WTFMove(buffer))
368         , m_currentOffset(0)
369     {
370     }
371
372     int readOutBytes(char* outputBuffer, unsigned askedToRead)
373     {
374         unsigned bytesLeft = m_buffer.size() - m_currentOffset;
375         unsigned lenToCopy = std::min(askedToRead, bytesLeft);
376         if (lenToCopy) {
377             memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy);
378             m_currentOffset += lenToCopy;
379         }
380         return lenToCopy;
381     }
382
383 private:
384     Vector<char> m_buffer;
385     unsigned m_currentOffset;
386 };
387
388 static inline void setAttributes(Element* element, Vector<Attribute>& attributeVector, ParserContentPolicy parserContentPolicy)
389 {
390     if (!scriptingContentIsAllowed(parserContentPolicy))
391         element->stripScriptingAttributes(attributeVector);
392     element->parserSetAttributes(attributeVector);
393 }
394
395 static void switchToUTF16(xmlParserCtxtPtr ctxt)
396 {
397     // Hack around libxml2's lack of encoding overide support by manually
398     // resetting the encoding to UTF-16 before every chunk.  Otherwise libxml
399     // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks
400     // and switch encodings, causing the parse to fail.
401
402     // FIXME: Can we just use XML_PARSE_IGNORE_ENC now?
403
404     const UChar BOM = 0xFEFF;
405     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
406     xmlSwitchEncoding(ctxt, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
407 }
408
409 static bool shouldAllowExternalLoad(const URL& url)
410 {
411     String urlString = url.string();
412
413     // On non-Windows platforms libxml asks for this URL, the
414     // "XML_XML_DEFAULT_CATALOG", on initialization.
415     if (urlString == "file:///etc/xml/catalog")
416         return false;
417
418     // On Windows, libxml computes a URL relative to where its DLL resides.
419     if (urlString.startsWith("file:///", false) && urlString.endsWith("/etc/catalog", false))
420         return false;
421
422     // The most common DTD.  There isn't much point in hammering www.w3c.org
423     // by requesting this URL for every XHTML document.
424     if (urlString.startsWith("http://www.w3.org/TR/xhtml", false))
425         return false;
426
427     // Similarly, there isn't much point in requesting the SVG DTD.
428     if (urlString.startsWith("http://www.w3.org/Graphics/SVG", false))
429         return false;
430
431     // The libxml doesn't give us a lot of context for deciding whether to
432     // allow this request.  In the worst case, this load could be for an
433     // external entity and the resulting document could simply read the
434     // retrieved content.  If we had more context, we could potentially allow
435     // the parser to load a DTD.  As things stand, we take the conservative
436     // route and allow same-origin requests only.
437     if (!XMLDocumentParserScope::currentCachedResourceLoader->document()->securityOrigin()->canRequest(url)) {
438         XMLDocumentParserScope::currentCachedResourceLoader->printAccessDeniedMessage(url);
439         return false;
440     }
441
442     return true;
443 }
444
445 static void* openFunc(const char* uri)
446 {
447     ASSERT(XMLDocumentParserScope::currentCachedResourceLoader);
448     ASSERT(currentThread() == libxmlLoaderThread);
449
450     URL url(URL(), uri);
451
452     if (!shouldAllowExternalLoad(url))
453         return &globalDescriptor;
454
455     ResourceError error;
456     ResourceResponse response;
457     RefPtr<SharedBuffer> data;
458
459
460     {
461         CachedResourceLoader* cachedResourceLoader = XMLDocumentParserScope::currentCachedResourceLoader;
462         XMLDocumentParserScope scope(nullptr);
463         // FIXME: We should restore the original global error handler as well.
464
465         if (cachedResourceLoader->frame())
466             cachedResourceLoader->frame()->loader().loadResourceSynchronously(url, AllowStoredCredentials, DoNotAskClientForCrossOriginCredentials, error, response, data);
467     }
468
469     // We have to check the URL again after the load to catch redirects.
470     // See <https://bugs.webkit.org/show_bug.cgi?id=21963>.
471     if (!shouldAllowExternalLoad(response.url()))
472         return &globalDescriptor;
473     Vector<char> buffer;
474     if (data)
475         buffer.append(data->data(), data->size());
476     return new OffsetBuffer(WTFMove(buffer));
477 }
478
479 static int readFunc(void* context, char* buffer, int len)
480 {
481     // Do 0-byte reads in case of a null descriptor
482     if (context == &globalDescriptor)
483         return 0;
484
485     OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
486     return data->readOutBytes(buffer, len);
487 }
488
489 static int writeFunc(void*, const char*, int)
490 {
491     // Always just do 0-byte writes
492     return 0;
493 }
494
495 static int closeFunc(void* context)
496 {
497     if (context != &globalDescriptor) {
498         OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
499         delete data;
500     }
501     return 0;
502 }
503
504 #if ENABLE(XSLT)
505 static void errorFunc(void*, const char*, ...)
506 {
507     // FIXME: It would be nice to display error messages somewhere.
508 }
509 #endif
510
511 static bool didInit = false;
512
513 Ref<XMLParserContext> XMLParserContext::createStringParser(xmlSAXHandlerPtr handlers, void* userData)
514 {
515     if (!didInit) {
516         xmlInitParser();
517         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
518         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
519         libxmlLoaderThread = currentThread();
520         didInit = true;
521     }
522
523     xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0);
524     parser->_private = userData;
525
526     // Substitute entities.
527     xmlCtxtUseOptions(parser, XML_PARSE_NOENT);
528
529     switchToUTF16(parser);
530
531     return adoptRef(*new XMLParserContext(parser));
532 }
533
534
535 // Chunk should be encoded in UTF-8
536 RefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerPtr handlers, void* userData, const CString& chunk)
537 {
538     if (!didInit) {
539         xmlInitParser();
540         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
541         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
542         libxmlLoaderThread = currentThread();
543         didInit = true;
544     }
545
546     // appendFragmentSource() checks that the length doesn't overflow an int.
547     xmlParserCtxtPtr parser = xmlCreateMemoryParserCtxt(chunk.data(), chunk.length());
548
549     if (!parser)
550         return 0;
551
552     memcpy(parser->sax, handlers, sizeof(xmlSAXHandler));
553
554     // Substitute entities.
555     // FIXME: Why is XML_PARSE_NODICT needed? This is different from what createStringParser does.
556     xmlCtxtUseOptions(parser, XML_PARSE_NODICT | XML_PARSE_NOENT);
557
558     // Internal initialization
559     parser->sax2 = 1;
560     parser->instate = XML_PARSER_CONTENT; // We are parsing a CONTENT
561     parser->depth = 0;
562     parser->str_xml = xmlDictLookup(parser->dict, BAD_CAST "xml", 3);
563     parser->str_xmlns = xmlDictLookup(parser->dict, BAD_CAST "xmlns", 5);
564     parser->str_xml_ns = xmlDictLookup(parser->dict, XML_XML_NAMESPACE, 36);
565     parser->_private = userData;
566
567     return adoptRef(*new XMLParserContext(parser));
568 }
569
570 // --------------------------------
571
572 bool XMLDocumentParser::supportsXMLVersion(const String& version)
573 {
574     return version == "1.0";
575 }
576
577 XMLDocumentParser::XMLDocumentParser(Document& document, FrameView* frameView)
578     : ScriptableDocumentParser(document)
579     , m_view(frameView)
580     , m_context(nullptr)
581     , m_pendingCallbacks(std::make_unique<PendingCallbacks>())
582     , m_depthTriggeringEntityExpansion(-1)
583     , m_isParsingEntityDeclaration(false)
584     , m_currentNode(&document)
585     , m_sawError(false)
586     , m_sawCSS(false)
587     , m_sawXSLTransform(false)
588     , m_sawFirstElement(false)
589     , m_isXHTMLDocument(false)
590     , m_parserPaused(false)
591     , m_requestingScript(false)
592     , m_finishCalled(false)
593     , m_pendingScript(nullptr)
594     , m_scriptStartPosition(TextPosition::belowRangePosition())
595     , m_parsingFragment(false)
596 {
597 }
598
599 XMLDocumentParser::XMLDocumentParser(DocumentFragment& fragment, Element* parentElement, ParserContentPolicy parserContentPolicy)
600     : ScriptableDocumentParser(fragment.document(), parserContentPolicy)
601     , m_view(nullptr)
602     , m_context(nullptr)
603     , m_pendingCallbacks(std::make_unique<PendingCallbacks>())
604     , m_depthTriggeringEntityExpansion(-1)
605     , m_isParsingEntityDeclaration(false)
606     , m_currentNode(&fragment)
607     , m_sawError(false)
608     , m_sawCSS(false)
609     , m_sawXSLTransform(false)
610     , m_sawFirstElement(false)
611     , m_isXHTMLDocument(false)
612     , m_parserPaused(false)
613     , m_requestingScript(false)
614     , m_finishCalled(false)
615     , m_pendingScript(0)
616     , m_scriptStartPosition(TextPosition::belowRangePosition())
617     , m_parsingFragment(true)
618 {
619     fragment.ref();
620
621     // Add namespaces based on the parent node
622     Vector<Element*> elemStack;
623     while (parentElement) {
624         elemStack.append(parentElement);
625
626         ContainerNode* node = parentElement->parentNode();
627         if (!is<Element>(node))
628             break;
629         parentElement = downcast<Element>(node);
630     }
631
632     if (elemStack.isEmpty())
633         return;
634
635     // FIXME: Share code with isDefaultNamespace() per http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#parsing-xhtml-fragments
636     for (; !elemStack.isEmpty(); elemStack.removeLast()) {
637         Element* element = elemStack.last();
638         if (element->hasAttributes()) {
639             for (const Attribute& attribute : element->attributesIterator()) {
640                 if (attribute.localName() == xmlnsAtom)
641                     m_defaultNamespaceURI = attribute.value();
642                 else if (attribute.prefix() == xmlnsAtom)
643                     m_prefixToNamespaceMap.set(attribute.localName(), attribute.value());
644             }
645         }
646     }
647
648     if (m_defaultNamespaceURI.isNull())
649         m_defaultNamespaceURI = parentElement->namespaceURI();
650 }
651
652 XMLParserContext::~XMLParserContext()
653 {
654     if (m_context->myDoc)
655         xmlFreeDoc(m_context->myDoc);
656     xmlFreeParserCtxt(m_context);
657 }
658
659 XMLDocumentParser::~XMLDocumentParser()
660 {
661     // The XMLDocumentParser will always be detached before being destroyed.
662     ASSERT(m_currentNodeStack.isEmpty());
663     ASSERT(!m_currentNode);
664
665     // FIXME: m_pendingScript handling should be moved into XMLDocumentParser.cpp!
666     if (m_pendingScript)
667         m_pendingScript->removeClient(this);
668 }
669
670 void XMLDocumentParser::doWrite(const String& parseString)
671 {
672     ASSERT(!isDetached());
673     if (!m_context)
674         initializeParserContext();
675
676     // Protect the libxml context from deletion during a callback
677     RefPtr<XMLParserContext> context = m_context;
678
679     // libXML throws an error if you try to switch the encoding for an empty string.
680     if (parseString.length()) {
681         // JavaScript may cause the parser to detach during xmlParseChunk
682         // keep this alive until this function is done.
683         Ref<XMLDocumentParser> protect(*this);
684
685         XMLDocumentParserScope scope(&document()->cachedResourceLoader());
686
687         // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
688         switchToUTF16(context->context());
689         xmlParseChunk(context->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), sizeof(UChar) * parseString.length(), 0);
690
691         // JavaScript (which may be run under the xmlParseChunk callstack) may
692         // cause the parser to be stopped or detached.
693         if (isStopped())
694             return;
695     }
696
697     // FIXME: Why is this here?  And why is it after we process the passed source?
698     if (document()->decoder() && document()->decoder()->sawError()) {
699         // If the decoder saw an error, report it as fatal (stops parsing)
700         TextPosition position(OrdinalNumber::fromOneBasedInt(context->context()->input->line), OrdinalNumber::fromOneBasedInt(context->context()->input->col));
701         handleError(XMLErrors::fatal, "Encoding error", position);
702     }
703 }
704
705 static inline String toString(const xmlChar* string, size_t size)
706 {
707     return String::fromUTF8(reinterpret_cast<const char*>(string), size);
708 }
709
710 static inline String toString(const xmlChar* string)
711 {
712     return String::fromUTF8(reinterpret_cast<const char*>(string));
713 }
714
715 static inline AtomicString toAtomicString(const xmlChar* string, size_t size)
716 {
717     return AtomicString::fromUTF8(reinterpret_cast<const char*>(string), size);
718 }
719
720 static inline AtomicString toAtomicString(const xmlChar* string)
721 {
722     return AtomicString::fromUTF8(reinterpret_cast<const char*>(string));
723 }
724
725 struct _xmlSAX2Namespace {
726     const xmlChar* prefix;
727     const xmlChar* uri;
728 };
729 typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
730
731 static inline void handleNamespaceAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlNamespaces, int nb_namespaces, ExceptionCode& ec)
732 {
733     xmlSAX2Namespace* namespaces = reinterpret_cast<xmlSAX2Namespace*>(libxmlNamespaces);
734     for (int i = 0; i < nb_namespaces; i++) {
735         AtomicString namespaceQName = xmlnsAtom;
736         AtomicString namespaceURI = toAtomicString(namespaces[i].uri);
737         if (namespaces[i].prefix)
738             namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
739
740         QualifiedName parsedName = anyName;
741         if (!Element::parseAttributeName(parsedName, XMLNSNames::xmlnsNamespaceURI, namespaceQName, ec))
742             return;
743         
744         prefixedAttributes.append(Attribute(parsedName, namespaceURI));
745     }
746 }
747
748 struct _xmlSAX2Attributes {
749     const xmlChar* localname;
750     const xmlChar* prefix;
751     const xmlChar* uri;
752     const xmlChar* value;
753     const xmlChar* end;
754 };
755 typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
756
757 static inline void handleElementAttributes(Vector<Attribute>& prefixedAttributes, const xmlChar** libxmlAttributes, int nb_attributes, ExceptionCode& ec)
758 {
759     xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
760     for (int i = 0; i < nb_attributes; i++) {
761         int valueLength = static_cast<int>(attributes[i].end - attributes[i].value);
762         AtomicString attrValue = toAtomicString(attributes[i].value, valueLength);
763         String attrPrefix = toString(attributes[i].prefix);
764         AtomicString attrURI = attrPrefix.isEmpty() ? AtomicString() : toAtomicString(attributes[i].uri);
765         AtomicString attrQName = attrPrefix.isEmpty() ? toAtomicString(attributes[i].localname) : attrPrefix + ":" + toString(attributes[i].localname);
766
767         QualifiedName parsedName = anyName;
768         if (!Element::parseAttributeName(parsedName, attrURI, attrQName, ec))
769             return;
770
771         prefixedAttributes.append(Attribute(parsedName, attrValue));
772     }
773 }
774
775 // This is a hack around https://bugzilla.gnome.org/show_bug.cgi?id=502960
776 // Otherwise libxml doesn't include namespace for parsed entities, breaking entity
777 // expansion for all entities containing elements.
778 static inline bool hackAroundLibXMLEntityParsingBug()
779 {
780 #if LIBXML_VERSION >= 20704
781     // This bug has been fixed in libxml 2.7.4.
782     return false;
783 #else
784     return true;
785 #endif
786 }
787
788 void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
789                                   const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
790 {
791     if (isStopped())
792         return;
793
794     if (m_parserPaused) {
795         m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces,
796                                                          nb_attributes, nb_defaulted, libxmlAttributes);
797         return;
798     }
799
800     if (!updateLeafTextNode())
801         return;
802
803     AtomicString localName = toAtomicString(xmlLocalName);
804     AtomicString uri = toAtomicString(xmlURI);
805     AtomicString prefix = toAtomicString(xmlPrefix);
806
807     if (m_parsingFragment && uri.isNull()) {
808         if (!prefix.isNull())
809             uri = m_prefixToNamespaceMap.get(prefix);
810         else
811             uri = m_defaultNamespaceURI;
812     }
813
814     // If libxml entity parsing is broken, transfer the currentNodes' namespaceURI to the new node,
815     // if we're currently expanding elements which originate from an entity declaration.
816     if (hackAroundLibXMLEntityParsingBug() && depthTriggeringEntityExpansion() != -1 && context()->depth > depthTriggeringEntityExpansion() && uri.isNull() && prefix.isNull())
817         uri = m_currentNode->namespaceURI();
818
819     bool isFirstElement = !m_sawFirstElement;
820     m_sawFirstElement = true;
821
822     QualifiedName qName(prefix, localName, uri);
823     auto newElement = m_currentNode->document().createElement(qName, true);
824
825     Vector<Attribute> prefixedAttributes;
826     ExceptionCode ec = 0;
827     handleNamespaceAttributes(prefixedAttributes, libxmlNamespaces, nb_namespaces, ec);
828     if (ec) {
829         setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy());
830         stopParsing();
831         return;
832     }
833
834     handleElementAttributes(prefixedAttributes, libxmlAttributes, nb_attributes, ec);
835     setAttributes(newElement.ptr(), prefixedAttributes, parserContentPolicy());
836     if (ec) {
837         stopParsing();
838         return;
839     }
840
841     newElement->beginParsingChildren();
842
843     ScriptElement* scriptElement = toScriptElementIfPossible(newElement.ptr());
844     if (scriptElement)
845         m_scriptStartPosition = textPosition();
846
847     m_currentNode->parserAppendChild(newElement.copyRef());
848     if (!m_currentNode) // Synchronous DOM events may have removed the current node.
849         return;
850
851 #if ENABLE(TEMPLATE_ELEMENT)
852     if (is<HTMLTemplateElement>(newElement))
853         pushCurrentNode(downcast<HTMLTemplateElement>(newElement.get()).content());
854     else
855         pushCurrentNode(newElement.ptr());
856 #else
857     pushCurrentNode(newElement.ptr());
858 #endif
859
860     if (is<HTMLHtmlElement>(newElement))
861         downcast<HTMLHtmlElement>(newElement.get()).insertedByParser();
862
863     if (!m_parsingFragment && isFirstElement && document()->frame())
864         document()->frame()->injectUserScripts(InjectAtDocumentStart);
865 }
866
867 void XMLDocumentParser::endElementNs()
868 {
869     if (isStopped())
870         return;
871
872     if (m_parserPaused) {
873         m_pendingCallbacks->appendEndElementNSCallback();
874         return;
875     }
876
877     // JavaScript can detach the parser.  Make sure this is not released
878     // before the end of this method.
879     Ref<XMLDocumentParser> protect(*this);
880
881     if (!updateLeafTextNode())
882         return;
883
884     RefPtr<ContainerNode> node = m_currentNode;
885     node->finishParsingChildren();
886
887     // Once we reach the depth again where entity expansion started, stop executing the work-around.
888     if (hackAroundLibXMLEntityParsingBug() && context()->depth <= depthTriggeringEntityExpansion())
889         setDepthTriggeringEntityExpansion(-1);
890
891     if (!scriptingContentIsAllowed(parserContentPolicy()) && is<Element>(*node) && toScriptElementIfPossible(downcast<Element>(node.get()))) {
892         popCurrentNode();
893         node->remove(IGNORE_EXCEPTION);
894         return;
895     }
896
897     if (!node->isElementNode() || !m_view) {
898         popCurrentNode();
899         return;
900     }
901
902     Element& element = downcast<Element>(*node);
903
904     // The element's parent may have already been removed from document.
905     // Parsing continues in this case, but scripts aren't executed.
906     if (!element.inDocument()) {
907         popCurrentNode();
908         return;
909     }
910
911     ScriptElement* scriptElement = toScriptElementIfPossible(&element);
912     if (!scriptElement) {
913         popCurrentNode();
914         return;
915     }
916
917     // Don't load external scripts for standalone documents (for now).
918     ASSERT(!m_pendingScript);
919     m_requestingScript = true;
920
921     if (scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute)) {
922         // FIXME: Script execution should be shared between
923         // the libxml2 and Qt XMLDocumentParser implementations.
924
925         if (scriptElement->readyToBeParserExecuted())
926             scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));
927         else if (scriptElement->willBeParserExecuted()) {
928             m_pendingScript = scriptElement->cachedScript();
929             m_scriptElement = &element;
930             m_pendingScript->addClient(this);
931
932             // m_pendingScript will be 0 if script was already loaded and addClient() executed it.
933             if (m_pendingScript)
934                 pauseParsing();
935         } else
936             m_scriptElement = nullptr;
937
938         // JavaScript may have detached the parser
939         if (isDetached())
940             return;
941     }
942     m_requestingScript = false;
943     popCurrentNode();
944 }
945
946 void XMLDocumentParser::characters(const xmlChar* s, int len)
947 {
948     if (isStopped())
949         return;
950
951     if (m_parserPaused) {
952         m_pendingCallbacks->appendCharactersCallback(s, len);
953         return;
954     }
955
956     if (!m_leafTextNode)
957         createLeafTextNode();
958     m_bufferedText.append(s, len);
959 }
960
961 void XMLDocumentParser::error(XMLErrors::ErrorType type, const char* message, va_list args)
962 {
963     if (isStopped())
964         return;
965
966 #if HAVE(VASPRINTF)
967     char* m;
968     if (vasprintf(&m, message, args) == -1)
969         return;
970 #else
971     char m[1024];
972     vsnprintf(m, sizeof(m) - 1, message, args);
973 #endif
974
975     TextPosition position = textPosition();
976     if (m_parserPaused)
977         m_pendingCallbacks->appendErrorCallback(type, reinterpret_cast<const xmlChar*>(m), position.m_line, position.m_column);
978     else
979         handleError(type, m, textPosition());
980
981 #if HAVE(VASPRINTF)
982     free(m);
983 #endif
984 }
985
986 void XMLDocumentParser::processingInstruction(const xmlChar* target, const xmlChar* data)
987 {
988     if (isStopped())
989         return;
990
991     if (m_parserPaused) {
992         m_pendingCallbacks->appendProcessingInstructionCallback(target, data);
993         return;
994     }
995
996     if (!updateLeafTextNode())
997         return;
998
999     // ### handle exceptions
1000     ExceptionCode ec = 0;
1001     Ref<ProcessingInstruction> pi = *m_currentNode->document().createProcessingInstruction(
1002         toString(target), toString(data), ec);
1003     if (ec)
1004         return;
1005
1006     pi->setCreatedByParser(true);
1007
1008     m_currentNode->parserAppendChild(pi.copyRef());
1009
1010     pi->finishParsingChildren();
1011
1012     if (pi->isCSS())
1013         m_sawCSS = true;
1014 #if ENABLE(XSLT)
1015     m_sawXSLTransform = !m_sawFirstElement && pi->isXSL();
1016     if (m_sawXSLTransform && !document()->transformSourceDocument())
1017         stopParsing();
1018 #endif
1019 }
1020
1021 void XMLDocumentParser::cdataBlock(const xmlChar* s, int len)
1022 {
1023     if (isStopped())
1024         return;
1025
1026     if (m_parserPaused) {
1027         m_pendingCallbacks->appendCDATABlockCallback(s, len);
1028         return;
1029     }
1030
1031     if (!updateLeafTextNode())
1032         return;
1033
1034     auto newNode = CDATASection::create(m_currentNode->document(), toString(s, len));
1035     m_currentNode->parserAppendChild(WTFMove(newNode));
1036 }
1037
1038 void XMLDocumentParser::comment(const xmlChar* s)
1039 {
1040     if (isStopped())
1041         return;
1042
1043     if (m_parserPaused) {
1044         m_pendingCallbacks->appendCommentCallback(s);
1045         return;
1046     }
1047
1048     if (!updateLeafTextNode())
1049         return;
1050
1051     auto newNode = Comment::create(m_currentNode->document(), toString(s));
1052     m_currentNode->parserAppendChild(WTFMove(newNode));
1053 }
1054
1055 enum StandaloneInfo {
1056     StandaloneUnspecified = -2,
1057     NoXMlDeclaration,
1058     StandaloneNo,
1059     StandaloneYes
1060 };
1061
1062 void XMLDocumentParser::startDocument(const xmlChar* version, const xmlChar* encoding, int standalone)
1063 {
1064     StandaloneInfo standaloneInfo = (StandaloneInfo)standalone;
1065     if (standaloneInfo == NoXMlDeclaration) {
1066         document()->setHasXMLDeclaration(false);
1067         return;
1068     }
1069
1070     if (version)
1071         document()->setXMLVersion(toString(version), ASSERT_NO_EXCEPTION);
1072     if (standalone != StandaloneUnspecified)
1073         document()->setXMLStandalone(standaloneInfo == StandaloneYes, ASSERT_NO_EXCEPTION);
1074     if (encoding)
1075         document()->setXMLEncoding(toString(encoding));
1076     document()->setHasXMLDeclaration(true);
1077 }
1078
1079 void XMLDocumentParser::endDocument()
1080 {
1081     updateLeafTextNode();
1082 }
1083
1084 void XMLDocumentParser::internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
1085 {
1086     if (isStopped())
1087         return;
1088
1089     if (m_parserPaused) {
1090         m_pendingCallbacks->appendInternalSubsetCallback(name, externalID, systemID);
1091         return;
1092     }
1093
1094     if (document())
1095         document()->parserAppendChild(DocumentType::create(*document(), toString(name), toString(externalID), toString(systemID)));
1096 }
1097
1098 static inline XMLDocumentParser* getParser(void* closure)
1099 {
1100     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1101     return static_cast<XMLDocumentParser*>(ctxt->_private);
1102 }
1103
1104 // This is a hack around http://bugzilla.gnome.org/show_bug.cgi?id=159219
1105 // Otherwise libxml seems to call all the SAX callbacks twice for any replaced entity.
1106 static inline bool hackAroundLibXMLEntityBug(void* closure)
1107 {
1108 #if LIBXML_VERSION >= 20627
1109     UNUSED_PARAM(closure);
1110
1111     // This bug has been fixed in libxml 2.6.27.
1112     return false;
1113 #else
1114     return static_cast<xmlParserCtxtPtr>(closure)->node;
1115 #endif
1116 }
1117
1118 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)
1119 {
1120     if (hackAroundLibXMLEntityBug(closure))
1121         return;
1122
1123     getParser(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1124 }
1125
1126 static void endElementNsHandler(void* closure, const xmlChar*, const xmlChar*, const xmlChar*)
1127 {
1128     if (hackAroundLibXMLEntityBug(closure))
1129         return;
1130
1131     getParser(closure)->endElementNs();
1132 }
1133
1134 static void charactersHandler(void* closure, const xmlChar* s, int len)
1135 {
1136     if (hackAroundLibXMLEntityBug(closure))
1137         return;
1138
1139     getParser(closure)->characters(s, len);
1140 }
1141
1142 static void processingInstructionHandler(void* closure, const xmlChar* target, const xmlChar* data)
1143 {
1144     if (hackAroundLibXMLEntityBug(closure))
1145         return;
1146
1147     getParser(closure)->processingInstruction(target, data);
1148 }
1149
1150 static void cdataBlockHandler(void* closure, const xmlChar* s, int len)
1151 {
1152     if (hackAroundLibXMLEntityBug(closure))
1153         return;
1154
1155     getParser(closure)->cdataBlock(s, len);
1156 }
1157
1158 static void commentHandler(void* closure, const xmlChar* comment)
1159 {
1160     if (hackAroundLibXMLEntityBug(closure))
1161         return;
1162
1163     getParser(closure)->comment(comment);
1164 }
1165
1166 WTF_ATTRIBUTE_PRINTF(2, 3)
1167 static void warningHandler(void* closure, const char* message, ...)
1168 {
1169     va_list args;
1170     va_start(args, message);
1171     getParser(closure)->error(XMLErrors::warning, message, args);
1172     va_end(args);
1173 }
1174
1175 WTF_ATTRIBUTE_PRINTF(2, 3)
1176 static void fatalErrorHandler(void* closure, const char* message, ...)
1177 {
1178     va_list args;
1179     va_start(args, message);
1180     getParser(closure)->error(XMLErrors::fatal, message, args);
1181     va_end(args);
1182 }
1183
1184 WTF_ATTRIBUTE_PRINTF(2, 3)
1185 static void normalErrorHandler(void* closure, const char* message, ...)
1186 {
1187     va_list args;
1188     va_start(args, message);
1189     getParser(closure)->error(XMLErrors::nonFatal, message, args);
1190     va_end(args);
1191 }
1192
1193 // Using a static entity and marking it XML_INTERNAL_PREDEFINED_ENTITY is
1194 // a hack to avoid malloc/free. Using a global variable like this could cause trouble
1195 // if libxml implementation details were to change
1196 static xmlChar sharedXHTMLEntityResult[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
1197
1198 static xmlEntityPtr sharedXHTMLEntity()
1199 {
1200     static xmlEntity entity;
1201     if (!entity.type) {
1202         entity.type = XML_ENTITY_DECL;
1203         entity.orig = sharedXHTMLEntityResult;
1204         entity.content = sharedXHTMLEntityResult;
1205         entity.etype = XML_INTERNAL_PREDEFINED_ENTITY;
1206     }
1207     return &entity;
1208 }
1209
1210 static size_t convertUTF16EntityToUTF8(const UChar* utf16Entity, size_t numberOfCodeUnits, char* target, size_t targetSize)
1211 {
1212     const char* originalTarget = target;
1213     WTF::Unicode::ConversionResult conversionResult = WTF::Unicode::convertUTF16ToUTF8(&utf16Entity,
1214         utf16Entity + numberOfCodeUnits, &target, target + targetSize);
1215     if (conversionResult != WTF::Unicode::conversionOK)
1216         return 0;
1217
1218     // Even though we must pass the length, libxml expects the entity string to be null terminated.
1219     ASSERT(target > originalTarget + 1);
1220     *target = '\0';
1221     return target - originalTarget;
1222 }
1223
1224 static xmlEntityPtr getXHTMLEntity(const xmlChar* name)
1225 {
1226     UChar utf16DecodedEntity[4];
1227     size_t numberOfCodeUnits = decodeNamedEntityToUCharArray(reinterpret_cast<const char*>(name), utf16DecodedEntity);
1228     if (!numberOfCodeUnits)
1229         return 0;
1230
1231     ASSERT(numberOfCodeUnits <= 4);
1232     size_t entityLengthInUTF8 = convertUTF16EntityToUTF8(utf16DecodedEntity, numberOfCodeUnits,
1233         reinterpret_cast<char*>(sharedXHTMLEntityResult), WTF_ARRAY_LENGTH(sharedXHTMLEntityResult));
1234     if (!entityLengthInUTF8)
1235         return 0;
1236
1237     xmlEntityPtr entity = sharedXHTMLEntity();
1238     entity->length = entityLengthInUTF8;
1239     entity->name = name;
1240     return entity;
1241 }
1242
1243 static void entityDeclarationHandler(void* closure, const xmlChar* name, int type, const xmlChar* publicId, const xmlChar* systemId, xmlChar* content)
1244 {
1245     // Prevent the next call to getEntityHandler() to record the entity expansion depth.
1246     // We're parsing the entity declaration, so there's no need to record anything.
1247     // We only need to record the depth, if we're actually expanding the entity, when it's referenced.
1248     if (hackAroundLibXMLEntityParsingBug())
1249         getParser(closure)->setIsParsingEntityDeclaration(true);
1250     xmlSAX2EntityDecl(closure, name, type, publicId, systemId, content);
1251 }
1252
1253 static xmlEntityPtr getEntityHandler(void* closure, const xmlChar* name)
1254 {
1255     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1256
1257     XMLDocumentParser* parser = getParser(closure);
1258     if (hackAroundLibXMLEntityParsingBug()) {
1259         if (parser->isParsingEntityDeclaration()) {
1260             // We're parsing the entity declarations (not an entity reference), no need to do anything special.
1261             parser->setIsParsingEntityDeclaration(false);
1262             ASSERT(parser->depthTriggeringEntityExpansion() == -1);
1263         } else {
1264             // The entity will be used and eventually expanded. Record the current parser depth
1265             // so the next call to startElementNs() knows that the new element originates from
1266             // an entity declaration.
1267             parser->setDepthTriggeringEntityExpansion(ctxt->depth);
1268         }
1269     }
1270
1271     xmlEntityPtr ent = xmlGetPredefinedEntity(name);
1272     if (ent) {
1273         ent->etype = XML_INTERNAL_PREDEFINED_ENTITY;
1274         return ent;
1275     }
1276
1277     ent = xmlGetDocEntity(ctxt->myDoc, name);
1278     if (!ent && parser->isXHTMLDocument()) {
1279         ent = getXHTMLEntity(name);
1280         if (ent)
1281             ent->etype = XML_INTERNAL_GENERAL_ENTITY;
1282     }
1283
1284     return ent;
1285 }
1286
1287 static void startDocumentHandler(void* closure)
1288 {
1289     xmlParserCtxt* ctxt = static_cast<xmlParserCtxt*>(closure);
1290     switchToUTF16(ctxt);
1291     getParser(closure)->startDocument(ctxt->version, ctxt->encoding, ctxt->standalone);
1292     xmlSAX2StartDocument(closure);
1293 }
1294
1295 static void endDocumentHandler(void* closure)
1296 {
1297     getParser(closure)->endDocument();
1298     xmlSAX2EndDocument(closure);
1299 }
1300
1301 static void internalSubsetHandler(void* closure, const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
1302 {
1303     getParser(closure)->internalSubset(name, externalID, systemID);
1304     xmlSAX2InternalSubset(closure, name, externalID, systemID);
1305 }
1306
1307 static void externalSubsetHandler(void* closure, const xmlChar*, const xmlChar* externalId, const xmlChar*)
1308 {
1309     String extId = toString(externalId);
1310     if ((extId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
1311         || (extId == "-//W3C//DTD XHTML 1.1//EN")
1312         || (extId == "-//W3C//DTD XHTML 1.0 Strict//EN")
1313         || (extId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
1314         || (extId == "-//W3C//DTD XHTML Basic 1.0//EN")
1315         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
1316         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
1317         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN")
1318         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.1//EN")
1319         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.2//EN"))
1320         getParser(closure)->setIsXHTMLDocument(true); // controls if we replace entities or not.
1321 }
1322
1323 static void ignorableWhitespaceHandler(void*, const xmlChar*, int)
1324 {
1325     // nothing to do, but we need this to work around a crasher
1326     // http://bugzilla.gnome.org/show_bug.cgi?id=172255
1327     // http://bugs.webkit.org/show_bug.cgi?id=5792
1328 }
1329
1330 void XMLDocumentParser::initializeParserContext(const CString& chunk)
1331 {
1332     xmlSAXHandler sax;
1333     memset(&sax, 0, sizeof(sax));
1334
1335     sax.error = normalErrorHandler;
1336     sax.fatalError = fatalErrorHandler;
1337     sax.characters = charactersHandler;
1338     sax.processingInstruction = processingInstructionHandler;
1339     sax.cdataBlock = cdataBlockHandler;
1340     sax.comment = commentHandler;
1341     sax.warning = warningHandler;
1342     sax.startElementNs = startElementNsHandler;
1343     sax.endElementNs = endElementNsHandler;
1344     sax.getEntity = getEntityHandler;
1345     sax.startDocument = startDocumentHandler;
1346     sax.endDocument = endDocumentHandler;
1347     sax.internalSubset = internalSubsetHandler;
1348     sax.externalSubset = externalSubsetHandler;
1349     sax.ignorableWhitespace = ignorableWhitespaceHandler;
1350     sax.entityDecl = entityDeclarationHandler;
1351     sax.initialized = XML_SAX2_MAGIC;
1352     DocumentParser::startParsing();
1353     m_sawError = false;
1354     m_sawCSS = false;
1355     m_sawXSLTransform = false;
1356     m_sawFirstElement = false;
1357
1358     XMLDocumentParserScope scope(&document()->cachedResourceLoader());
1359     if (m_parsingFragment)
1360         m_context = XMLParserContext::createMemoryParser(&sax, this, chunk);
1361     else {
1362         ASSERT(!chunk.data());
1363         m_context = XMLParserContext::createStringParser(&sax, this);
1364     }
1365 }
1366
1367 void XMLDocumentParser::doEnd()
1368 {
1369     if (!isStopped()) {
1370         if (m_context) {
1371             // Tell libxml we're done.
1372             {
1373                 XMLDocumentParserScope scope(&document()->cachedResourceLoader());
1374                 xmlParseChunk(context(), 0, 0, 1);
1375             }
1376
1377             m_context = nullptr;
1378         }
1379     }
1380
1381 #if ENABLE(XSLT)
1382     bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && hasNoStyleInformation(document());
1383     if (xmlViewerMode) {
1384         XMLTreeViewer xmlTreeViewer(*document());
1385         xmlTreeViewer.transformDocumentToTreeView();
1386     } else if (m_sawXSLTransform) {
1387         void* doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform.toString(), document()->url().string());
1388         document()->setTransformSource(std::make_unique<TransformSource>(doc));
1389
1390         document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets.
1391         document()->styleResolverChanged(RecalcStyleImmediately);
1392
1393         // styleResolverChanged() call can detach the parser and null out its document.
1394         // In that case, we just bail out.
1395         if (isDetached())
1396             return;
1397
1398         document()->setParsing(true);
1399         DocumentParser::stopParsing();
1400     }
1401 #endif
1402 }
1403
1404 #if ENABLE(XSLT)
1405 static inline const char* nativeEndianUTF16Encoding()
1406 {
1407     const UChar BOM = 0xFEFF;
1408     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
1409     return BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE";
1410 }
1411
1412 void* xmlDocPtrForString(CachedResourceLoader& cachedResourceLoader, const String& source, const String& url)
1413 {
1414     if (source.isEmpty())
1415         return nullptr;
1416
1417     // Parse in a single chunk into an xmlDocPtr
1418     // FIXME: Hook up error handlers so that a failure to parse the main document results in
1419     // good error messages.
1420
1421     const bool is8Bit = source.is8Bit();
1422     const char* characters = is8Bit ? reinterpret_cast<const char*>(source.characters8()) : reinterpret_cast<const char*>(source.characters16());
1423     size_t sizeInBytes = source.length() * (is8Bit ? sizeof(LChar) : sizeof(UChar));
1424     const char* encoding = is8Bit ? "iso-8859-1" : nativeEndianUTF16Encoding();
1425
1426     XMLDocumentParserScope scope(&cachedResourceLoader, errorFunc);
1427     return xmlReadMemory(characters, sizeInBytes, url.latin1().data(), encoding, XSLT_PARSE_OPTIONS);
1428 }
1429 #endif
1430
1431 TextPosition XMLDocumentParser::textPosition() const
1432 {
1433     xmlParserCtxtPtr context = this->context();
1434     if (!context)
1435         return TextPosition::minimumPosition();
1436     return TextPosition(OrdinalNumber::fromOneBasedInt(context->input->line),
1437                         OrdinalNumber::fromOneBasedInt(context->input->col));
1438 }
1439
1440 bool XMLDocumentParser::shouldAssociateConsoleMessagesWithTextPosition() const
1441 {
1442     return !m_parserPaused && !m_requestingScript;
1443 }
1444
1445 void XMLDocumentParser::stopParsing()
1446 {
1447     DocumentParser::stopParsing();
1448     if (context())
1449         xmlStopParser(context());
1450 }
1451
1452 void XMLDocumentParser::resumeParsing()
1453 {
1454     ASSERT(!isDetached());
1455     ASSERT(m_parserPaused);
1456
1457     m_parserPaused = false;
1458
1459     // First, execute any pending callbacks
1460     while (!m_pendingCallbacks->isEmpty()) {
1461         m_pendingCallbacks->callAndRemoveFirstCallback(this);
1462
1463         // A callback paused the parser
1464         if (m_parserPaused)
1465             return;
1466     }
1467
1468     // Then, write any pending data
1469     SegmentedString rest = m_pendingSrc;
1470     m_pendingSrc.clear();
1471     // There is normally only one string left, so toString() shouldn't copy.
1472     // In any case, the XML parser runs on the main thread and it's OK if
1473     // the passed string has more than one reference.
1474     append(rest.toString().impl());
1475
1476     // Finally, if finish() has been called and write() didn't result
1477     // in any further callbacks being queued, call end()
1478     if (m_finishCalled && m_pendingCallbacks->isEmpty())
1479         end();
1480 }
1481
1482 bool XMLDocumentParser::appendFragmentSource(const String& chunk)
1483 {
1484     ASSERT(!m_context);
1485     ASSERT(m_parsingFragment);
1486
1487     CString chunkAsUtf8 = chunk.utf8();
1488     
1489     // libxml2 takes an int for a length, and therefore can't handle XML chunks larger than 2 GiB.
1490     if (chunkAsUtf8.length() > INT_MAX)
1491         return false;
1492
1493     initializeParserContext(chunkAsUtf8);
1494     xmlParseContent(context());
1495     endDocument(); // Close any open text nodes.
1496
1497     // FIXME: If this code is actually needed, it should probably move to finish()
1498     // XMLDocumentParserQt has a similar check (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError) in doEnd().
1499     // Check if all the chunk has been processed.
1500     long bytesProcessed = xmlByteConsumed(context());
1501     if (bytesProcessed == -1 || ((unsigned long)bytesProcessed) != chunkAsUtf8.length()) {
1502         // FIXME: I don't believe we can hit this case without also having seen an error or a null byte.
1503         // If we hit this ASSERT, we've found a test case which demonstrates the need for this code.
1504         ASSERT(m_sawError || (bytesProcessed >= 0 && !chunkAsUtf8.data()[bytesProcessed]));
1505         return false;
1506     }
1507
1508     // No error if the chunk is well formed or it is not but we have no error.
1509     return context()->wellFormed || !xmlCtxtGetLastError(context());
1510 }
1511
1512 // --------------------------------
1513
1514 struct AttributeParseState {
1515     HashMap<String, String> attributes;
1516     bool gotAttributes;
1517 };
1518
1519 static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLocalName, const xmlChar* /*xmlPrefix*/,
1520                                             const xmlChar* /*xmlURI*/, int /*nb_namespaces*/, const xmlChar** /*namespaces*/,
1521                                             int nb_attributes, int /*nb_defaulted*/, const xmlChar** libxmlAttributes)
1522 {
1523     if (strcmp(reinterpret_cast<const char*>(xmlLocalName), "attrs") != 0)
1524         return;
1525
1526     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1527     AttributeParseState* state = static_cast<AttributeParseState*>(ctxt->_private);
1528
1529     state->gotAttributes = true;
1530
1531     xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
1532     for (int i = 0; i < nb_attributes; i++) {
1533         String attrLocalName = toString(attributes[i].localname);
1534         int valueLength = (int) (attributes[i].end - attributes[i].value);
1535         String attrValue = toString(attributes[i].value, valueLength);
1536         String attrPrefix = toString(attributes[i].prefix);
1537         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
1538
1539         state->attributes.set(attrQName, attrValue);
1540     }
1541 }
1542
1543 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
1544 {
1545     String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
1546
1547     AttributeParseState state;
1548     state.gotAttributes = false;
1549
1550     xmlSAXHandler sax;
1551     memset(&sax, 0, sizeof(sax));
1552     sax.startElementNs = attributesStartElementNsHandler;
1553     sax.initialized = XML_SAX2_MAGIC;
1554
1555     RefPtr<XMLParserContext> parser = XMLParserContext::createStringParser(&sax, &state);
1556
1557     // FIXME: Can we parse 8-bit strings directly as Latin-1 instead of upconverting to UTF-16?
1558     xmlParseChunk(parser->context(), reinterpret_cast<const char*>(StringView(parseString).upconvertedCharacters().get()), parseString.length() * sizeof(UChar), 1);
1559
1560     attrsOK = state.gotAttributes;
1561     return WTFMove(state.attributes);
1562 }
1563
1564 }