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