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