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