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