38a380a5faf0dfb414a847b20be49b0c43d87b6c
[WebKit-https.git] / WebCore / dom / XMLTokenizer.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
5  * Copyright (C) 2005, 2006 Apple Computer, Inc.
6  * Copyright (C) 2006 Alexey Proskuryakov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "config.h"
25 #include "XMLTokenizer.h"
26
27 #include "CDATASection.h"
28 #include "CString.h"
29 #include "Cache.h"
30 #include "CachedScript.h"
31 #include "Comment.h"
32 #include "DocLoader.h"
33 #include "Document.h"
34 #include "DocumentFragment.h"
35 #include "DocumentType.h"
36 #include "EventNames.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "FrameView.h"
40 #include "HTMLNames.h"
41 #include "HTMLScriptElement.h"
42 #include "HTMLTableSectionElement.h"
43 #include "HTMLTokenizer.h"
44 #include "LoaderFunctions.h"
45 #include "ProcessingInstruction.h"
46 #include "ResourceHandle.h"
47 #include "ResourceRequest.h"
48 #include "ResourceResponse.h"
49 #include <libxml/parser.h>
50 #include <libxml/parserInternals.h>
51 #include <wtf/Platform.h>
52 #include <wtf/Vector.h>
53
54 #ifdef XSLT_SUPPORT
55 #include <libxslt/xslt.h>
56 #endif
57
58 #ifdef SVG_SUPPORT
59 #include "SVGNames.h"
60 #include "XLinkNames.h"
61 #endif
62
63 using namespace std;
64
65 namespace WebCore {
66
67 using namespace EventNames;
68 using namespace HTMLNames;
69
70 const int maxErrors = 25;
71
72 typedef HashMap<StringImpl*, StringImpl*> PrefixForNamespaceMap;
73
74 class PendingCallbacks;
75
76 class XMLTokenizer : public Tokenizer, public CachedResourceClient {
77 public:
78     XMLTokenizer(Document *, FrameView * = 0);
79     XMLTokenizer(DocumentFragment *, Element *);
80     ~XMLTokenizer();
81
82     enum ErrorType { warning, nonFatal, fatal };
83
84     // from Tokenizer
85     virtual bool write(const SegmentedString &str, bool);
86     virtual void finish();
87     virtual bool isWaitingForScripts() const;
88     virtual void stopParsing();
89
90     void end();
91
92     void pauseParsing();
93     void resumeParsing();
94     
95     void setIsXHTMLDocument(bool isXHTML) { m_isXHTMLDocument = isXHTML; }
96     bool isXHTMLDocument() const { return m_isXHTMLDocument; }
97
98     // from CachedResourceClient
99     virtual void notifyFinished(CachedResource *finishedObj);
100
101     // callbacks from parser SAX
102     void error(ErrorType, const char *message, va_list args);
103     void startElementNs(const xmlChar *xmlLocalName, const xmlChar *xmlPrefix, const xmlChar *xmlURI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **libxmlAttributes);
104     void endElementNs();
105     void characters(const xmlChar *s, int len);
106     void processingInstruction(const xmlChar *target, const xmlChar *data);
107     void cdataBlock(const xmlChar *s, int len);
108     void comment(const xmlChar *s);
109     void internalSubset(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID);
110
111     void handleError(ErrorType type, const char* m, int lineNumber, int columnNumber);
112     
113 private:
114     void initializeParserContext();
115     void setCurrentNode(Node*);
116
117     int lineNumber() const;
118     int columnNumber() const;
119
120     void insertErrorMessageBlock();
121
122     bool enterText();
123     void exitText();
124
125     Document *m_doc;
126     FrameView *m_view;
127     
128     String m_originalSourceForTransform;
129
130     xmlParserCtxtPtr m_context;
131     Node *m_currentNode;
132     bool m_currentNodeIsReferenced;
133
134     bool m_sawError;
135     bool m_sawXSLTransform;
136     bool m_sawFirstElement;
137     bool m_isXHTMLDocument;
138     
139     bool m_parserPaused;
140     bool m_requestingScript;
141     bool m_finishCalled;
142     
143     int m_errorCount;
144     int m_lastErrorLine;
145     int m_lastErrorColumn;
146     String m_errorMessages;
147
148     CachedScript *m_pendingScript;
149     RefPtr<Element> m_scriptElement;
150     int m_scriptStartLine;
151     
152     bool m_parsingFragment;
153     String m_defaultNamespaceURI;
154     PrefixForNamespaceMap m_prefixToNamespaceMap;
155     
156     PendingCallbacks* m_pendingCallbacks;
157     SegmentedString m_pendingSrc;
158 };
159
160 class PendingCallbacks {
161 public:
162     PendingCallbacks()
163     {
164         m_callbacks.setAutoDelete(true);
165     }
166     
167     void appendStartElementNSCallback(const xmlChar *xmlLocalName, const xmlChar *xmlPrefix, const xmlChar *xmlURI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
168     {
169         PendingStartElementNSCallback* callback = new PendingStartElementNSCallback;
170         
171         callback->xmlLocalName = xmlStrdup(xmlLocalName);
172         callback->xmlPrefix = xmlStrdup(xmlPrefix);
173         callback->xmlURI = xmlStrdup(xmlURI);
174         callback->nb_namespaces = nb_namespaces;
175         callback->namespaces = reinterpret_cast<xmlChar**>(xmlMalloc(sizeof (xmlChar*) * nb_namespaces * 2));
176         for (int i = 0; i < nb_namespaces * 2 ; i++)
177             callback->namespaces[i] = xmlStrdup(namespaces[i]);
178         callback->nb_attributes = nb_attributes;
179         callback->nb_defaulted = nb_defaulted;
180         callback->attributes =  reinterpret_cast<xmlChar**>(xmlMalloc(sizeof (xmlChar*) * nb_attributes * 5));
181         for (int i = 0; i < nb_attributes; i++) {
182             // Each attribute has 5 elements in the array:
183             // name, prefix, uri, value and an end pointer.
184             
185             for (int j = 0; j < 3; j++)
186                 callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]);
187             
188             int len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
189
190             callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len);
191             callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len;
192         }
193         
194         m_callbacks.append(callback);
195     }
196
197     void appendEndElementNSCallback()
198     {
199         PendingEndElementNSCallback* callback = new PendingEndElementNSCallback;
200         
201         m_callbacks.append(callback);
202     }
203     
204     void appendCharactersCallback(const xmlChar *s, int len)
205     {
206         PendingCharactersCallback* callback = new PendingCharactersCallback;
207         
208         callback->s = xmlStrndup(s, len);
209         callback->len = len;
210         
211         m_callbacks.append(callback);        
212     }
213     
214     void appendProcessingInstructionCallback(const xmlChar *target, const xmlChar *data)
215     {
216         PendingProcessingInstructionCallback* callback = new PendingProcessingInstructionCallback;
217         
218         callback->target = xmlStrdup(target);
219         callback->data = xmlStrdup(data);
220         
221         m_callbacks.append(callback);
222     }
223     
224     void appendCDATABlockCallback(const xmlChar *s, int len)
225     {
226         PendingCDATABlockCallback* callback = new PendingCDATABlockCallback;
227         
228         callback->s = xmlStrndup(s, len);
229         callback->len = len;
230         
231         m_callbacks.append(callback);        
232     }
233
234     void appendCommentCallback(const xmlChar *s)
235     {
236         PendingCommentCallback* callback = new PendingCommentCallback;
237         
238         callback->s = xmlStrdup(s);
239         
240         m_callbacks.append(callback);        
241     }
242
243     void appendInternalSubsetCallback(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
244     {
245         PendingInternalSubsetCallback* callback = new PendingInternalSubsetCallback;
246         
247         callback->name = xmlStrdup(name);
248         callback->externalID = xmlStrdup(externalID);
249         callback->systemID = xmlStrdup(systemID);
250         
251         m_callbacks.append(callback);        
252     }
253     
254     void appendErrorCallback(XMLTokenizer::ErrorType type, const char* message, int lineNumber, int columnNumber)
255     {
256         PendingErrorCallback* callback = new PendingErrorCallback;
257         
258         callback->message = strdup(message);
259         callback->type = type;
260         callback->lineNumber = lineNumber;
261         callback->columnNumber = columnNumber;
262         
263         m_callbacks.append(callback);
264     }
265
266     void callAndRemoveFirstCallback(XMLTokenizer* tokenizer)
267     {
268         PendingCallback *cb = m_callbacks.getFirst();
269             
270         cb->call(tokenizer);
271         m_callbacks.removeFirst();
272     }
273     
274     bool isEmpty() const { return m_callbacks.isEmpty(); }
275     
276 private:    
277     struct PendingCallback {        
278         
279         virtual ~PendingCallback() { } 
280
281         virtual void call(XMLTokenizer* tokenizer) = 0;
282     };  
283     
284     struct PendingStartElementNSCallback : public PendingCallback {        
285         virtual ~PendingStartElementNSCallback() {
286             xmlFree(xmlLocalName);
287             xmlFree(xmlPrefix);
288             xmlFree(xmlURI);
289             for (int i = 0; i < nb_namespaces * 2; i++)
290                 xmlFree(namespaces[i]);
291             xmlFree(namespaces);
292             for (int i = 0; i < nb_attributes; i++)
293                 for (int j = 0; j < 4; j++) 
294                     xmlFree(attributes[i * 5 + j]);
295             xmlFree(attributes);
296         }
297         
298         virtual void call(XMLTokenizer* tokenizer) {
299             tokenizer->startElementNs(xmlLocalName, xmlPrefix, xmlURI, 
300                                       nb_namespaces, (const xmlChar**)namespaces,
301                                       nb_attributes, nb_defaulted, (const xmlChar**)(attributes));
302         }
303
304         xmlChar* xmlLocalName;
305         xmlChar* xmlPrefix;
306         xmlChar* xmlURI;
307         int nb_namespaces;
308         xmlChar** namespaces;
309         int nb_attributes;
310         int nb_defaulted;
311         xmlChar** attributes;
312     };
313     
314     struct PendingEndElementNSCallback : public PendingCallback {
315         virtual void call(XMLTokenizer* tokenizer) 
316         {
317             tokenizer->endElementNs();
318         }
319     };
320     
321     struct PendingCharactersCallback : public PendingCallback {
322         virtual ~PendingCharactersCallback() 
323         {
324             xmlFree(s);
325         }
326     
327         virtual void call(XMLTokenizer* tokenizer) 
328         {
329             tokenizer->characters(s, len);
330         }
331         
332         xmlChar* s;
333         int len;
334     };
335
336     struct PendingProcessingInstructionCallback : public PendingCallback {
337         virtual ~PendingProcessingInstructionCallback() 
338         {
339             xmlFree(target);
340             xmlFree(data);
341         }
342         
343         virtual void call(XMLTokenizer* tokenizer) 
344         {
345             tokenizer->processingInstruction(target, data);
346         }
347         
348         xmlChar* target;
349         xmlChar* data;
350     };
351     
352     struct PendingCDATABlockCallback : public PendingCallback {
353         virtual ~PendingCDATABlockCallback() 
354         {
355             xmlFree(s);
356         }
357         
358         virtual void call(XMLTokenizer* tokenizer) 
359         {
360             tokenizer->cdataBlock(s, len);
361         }
362         
363         xmlChar* s;
364         int len;
365     };
366
367     struct PendingCommentCallback : public PendingCallback {
368         virtual ~PendingCommentCallback() 
369         {
370             xmlFree(s);
371         }
372         
373         virtual void call(XMLTokenizer* tokenizer) 
374         {
375             tokenizer->comment(s);
376         }
377
378         xmlChar* s;
379     };
380     
381     struct PendingInternalSubsetCallback : public PendingCallback {
382         virtual ~PendingInternalSubsetCallback() 
383         {
384             xmlFree(name);
385             xmlFree(externalID);
386             xmlFree(systemID);
387         }
388         
389         virtual void call(XMLTokenizer* tokenizer)
390         {
391             tokenizer->internalSubset(name, externalID, systemID);
392         }
393         
394         xmlChar* name;
395         xmlChar* externalID;
396         xmlChar* systemID;        
397     };
398     
399     struct PendingErrorCallback: public PendingCallback {
400         virtual ~PendingErrorCallback() 
401         {
402             free (message);
403         }
404         
405         virtual void call(XMLTokenizer* tokenizer) 
406         {
407             tokenizer->handleError(type, message, lineNumber, columnNumber);
408         }
409         
410         XMLTokenizer::ErrorType type;
411         char* message;
412         int lineNumber;
413         int columnNumber;
414     };
415     
416 public:
417     DeprecatedPtrList<PendingCallback> m_callbacks;
418 };
419
420 // --------------------------------
421
422 static int globalDescriptor = 0;
423
424 static int matchFunc(const char* uri)
425 {
426     return 1; // Match everything.
427 }
428
429 static DocLoader *globalDocLoader = 0;
430
431 class OffsetBuffer {
432 public:
433     OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { }
434     
435     int readOutBytes(char *outputBuffer, unsigned askedToRead) {
436         unsigned bytesLeft = m_buffer.size() - m_currentOffset;
437         unsigned lenToCopy = min(askedToRead, bytesLeft);
438         if (lenToCopy) {
439             memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy);
440             m_currentOffset += lenToCopy;
441         }
442         return lenToCopy;
443     }
444
445 private:
446     Vector<char> m_buffer;
447     unsigned m_currentOffset;
448 };
449
450 static bool shouldAllowExternalLoad(const char* inURI)
451 {
452     if (strstr(inURI, "/etc/xml/catalog")
453             || strstr(inURI, "http://www.w3.org/Graphics/SVG") == inURI
454             || strstr(inURI, "http://www.w3.org/TR/xhtml") == inURI)
455         return false;
456     return true;
457 }
458
459 static void* openFunc(const char* uri)
460 {
461     if (!globalDocLoader || !shouldAllowExternalLoad(uri))
462         return &globalDescriptor;
463
464     ResourceResponse response;
465     Vector<char> data = ServeSynchronousRequest(cache()->loader(), globalDocLoader, KURL(uri), response);
466     
467     return new OffsetBuffer(data);
468 }
469
470 static int readFunc(void* context, char* buffer, int len)
471 {
472     // Do 0-byte reads in case of a null descriptor
473     if (context == &globalDescriptor)
474         return 0;
475         
476     OffsetBuffer *data = static_cast<OffsetBuffer *>(context);
477     return data->readOutBytes(buffer, len);
478 }
479
480 static int writeFunc(void* context, const char* buffer, int len)
481 {
482     // Always just do 0-byte writes
483     return 0;
484 }
485
486 static int closeFunc(void * context)
487 {
488     if (context != &globalDescriptor) {
489         OffsetBuffer *data = static_cast<OffsetBuffer *>(context);
490         delete data;
491     }
492     return 0;
493 }
494
495 static void errorFunc(void*, const char*, ...)
496 {
497     // FIXME: It would be nice to display error messages somewhere.
498 }
499
500 void setLoaderForLibXMLCallbacks(DocLoader *docLoader)
501 {
502     globalDocLoader = docLoader;
503 }
504
505 static xmlParserCtxtPtr createStringParser(xmlSAXHandlerPtr handlers, void* userData)
506 {
507     static bool didInit = false;
508     if (!didInit) {
509         xmlInitParser();
510         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
511         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
512         didInit = true;
513     }
514
515     xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0);
516     parser->_private = userData;
517     parser->replaceEntities = true;
518     const UChar BOM = 0xFEFF;
519     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
520     xmlSwitchEncoding(parser, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
521     return parser;
522 }
523
524 // --------------------------------
525
526 XMLTokenizer::XMLTokenizer(Document *_doc, FrameView *_view)
527     : m_doc(_doc)
528     , m_view(_view)
529     , m_context(0)
530     , m_currentNode(_doc)
531     , m_currentNodeIsReferenced(false)
532     , m_sawError(false)
533     , m_sawXSLTransform(false)
534     , m_sawFirstElement(false)
535     , m_isXHTMLDocument(false)
536     , m_parserPaused(false)
537     , m_requestingScript(false)
538     , m_finishCalled(false)
539     , m_errorCount(0)
540     , m_lastErrorLine(0)
541     , m_lastErrorColumn(0)
542     , m_pendingScript(0)
543     , m_scriptStartLine(0)
544     , m_parsingFragment(false)
545     , m_pendingCallbacks(new PendingCallbacks)
546 {
547 }
548
549 XMLTokenizer::XMLTokenizer(DocumentFragment *fragment, Element *parentElement)
550     : m_doc(fragment->document())
551     , m_view(0)
552     , m_context(0)
553     , m_currentNode(fragment)
554     , m_currentNodeIsReferenced(fragment)
555     , m_sawError(false)
556     , m_sawXSLTransform(false)
557     , m_sawFirstElement(false)
558     , m_isXHTMLDocument(false)
559     , m_parserPaused(false)
560     , m_requestingScript(false)
561     , m_finishCalled(false)
562     , m_errorCount(0)
563     , m_lastErrorLine(0)
564     , m_lastErrorColumn(0)
565     , m_pendingScript(0)
566     , m_scriptStartLine(0)
567     , m_parsingFragment(true)
568     , m_pendingCallbacks(new PendingCallbacks)
569 {
570     if (fragment)
571         fragment->ref();
572     if (m_doc)
573         m_doc->ref();
574           
575     // Add namespaces based on the parent node
576     Vector<Element*> elemStack;
577     while (parentElement) {
578         elemStack.append(parentElement);
579         
580         Node *n = parentElement->parentNode();
581         if (!n || !n->isElementNode())
582             break;
583         parentElement = static_cast<Element *>(n);
584     }
585     
586     if (elemStack.isEmpty())
587         return;
588     
589     for (Element *element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
590         if (NamedAttrMap *attrs = element->attributes()) {
591             for (unsigned i = 0; i < attrs->length(); i++) {
592                 Attribute *attr = attrs->attributeItem(i);
593                 if (attr->localName() == "xmlns")
594                     m_defaultNamespaceURI = attr->value();
595                 else if (attr->prefix() == "xmlns")
596                     m_prefixToNamespaceMap.set(attr->localName().impl(), attr->value().impl());
597             }
598         }
599     }
600 }
601
602 XMLTokenizer::~XMLTokenizer()
603 {
604     setCurrentNode(0);
605     if (m_parsingFragment && m_doc)
606         m_doc->deref();
607     delete m_pendingCallbacks;
608     if (m_pendingScript)
609         m_pendingScript->deref(this);
610 }
611
612 void XMLTokenizer::setCurrentNode(Node* n)
613 {
614     bool nodeNeedsReference = n && n != m_doc;
615     if (nodeNeedsReference)
616         n->ref(); 
617     if (m_currentNodeIsReferenced) 
618         m_currentNode->deref(); 
619     m_currentNode = n;
620     m_currentNodeIsReferenced = nodeNeedsReference;
621 }
622
623 bool XMLTokenizer::write(const SegmentedString& s, bool /*appendData*/)
624 {
625     String parseString = s.toString();
626     
627     if (m_sawXSLTransform || !m_sawFirstElement)
628         m_originalSourceForTransform += parseString;
629
630     if (m_parserStopped || m_sawXSLTransform)
631         return false;
632     
633     if (m_parserPaused) {
634         m_pendingSrc.append(s);
635         return false;
636     }
637     
638     if (!m_context)
639         initializeParserContext();
640     
641     // libXML throws an error if you try to switch the encoding for an empty string.
642     if (parseString.length()) {
643         // Hack around libxml2's lack of encoding overide support by manually
644         // resetting the encoding to UTF-16 before every chunk.  Otherwise libxml
645         // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks 
646         // and switch encodings, causing the parse to fail.
647         const UChar BOM = 0xFEFF;
648         const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
649         xmlSwitchEncoding(m_context, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
650
651         xmlParseChunk(m_context, reinterpret_cast<const char*>(parseString.characters()), sizeof(UChar) * parseString.length(), 0);
652     }
653     
654     return false;
655 }
656
657 inline String toString(const xmlChar* str, unsigned len)
658 {
659     return UTF8Encoding().decode(reinterpret_cast<const char*>(str), len);
660 }
661
662 inline String toString(const xmlChar* str)
663 {
664     const char* cstr = str ? reinterpret_cast<const char*>(str) : "";
665     return UTF8Encoding().decode(cstr, strlen(cstr));
666 }
667
668 struct _xmlSAX2Namespace {
669     const xmlChar *prefix;
670     const xmlChar *uri;
671 };
672 typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
673
674 static inline void handleElementNamespaces(Element *newElement, const xmlChar **libxmlNamespaces, int nb_namespaces, ExceptionCode& ec)
675 {
676     xmlSAX2Namespace *namespaces = reinterpret_cast<xmlSAX2Namespace *>(libxmlNamespaces);
677     for(int i = 0; i < nb_namespaces; i++) {
678         String namespaceQName = "xmlns";
679         String namespaceURI = toString(namespaces[i].uri);
680         if (namespaces[i].prefix)
681             namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
682         newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
683         if (ec) // exception setting attributes
684             return;
685     }
686 }
687
688 struct _xmlSAX2Attributes {
689     const xmlChar *localname;
690     const xmlChar *prefix;
691     const xmlChar *uri;
692     const xmlChar *value;
693     const xmlChar *end;
694 };
695 typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
696
697 static inline void handleElementAttributes(Element *newElement, const xmlChar **libxmlAttributes, int nb_attributes, ExceptionCode& ec)
698 {
699     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
700     for(int i = 0; i < nb_attributes; i++) {
701         String attrLocalName = toString(attributes[i].localname);
702         int valueLength = (int) (attributes[i].end - attributes[i].value);
703         String attrValue = toString(attributes[i].value, valueLength);
704         String attrPrefix = toString(attributes[i].prefix);
705         String attrURI = attrPrefix.isEmpty() ? String() : toString(attributes[i].uri);
706         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
707         
708         newElement->setAttributeNS(attrURI, attrQName, attrValue, ec);
709         if (ec) // exception setting attributes
710             return;
711     }
712 }
713
714 void XMLTokenizer::startElementNs(const xmlChar *xmlLocalName, const xmlChar *xmlPrefix, const xmlChar *xmlURI, int nb_namespaces, const xmlChar **libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar **libxmlAttributes)
715 {
716     if (m_parserStopped)
717         return;
718     
719     if (m_parserPaused) {        
720         m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, nb_attributes, nb_defaulted, libxmlAttributes);
721         return;
722     }
723     
724     m_sawFirstElement = true;
725
726     exitText();
727
728     String localName = toString(xmlLocalName);
729     String uri = toString(xmlURI);
730     String prefix = toString(xmlPrefix);
731     String qName = prefix.isEmpty() ? localName : prefix + ":" + localName;
732     
733     if (m_parsingFragment && uri.isEmpty()) {
734         if (!prefix.isEmpty())
735             uri = String(m_prefixToNamespaceMap.get(prefix.impl()));
736         else
737             uri = m_defaultNamespaceURI;
738     }
739
740     ExceptionCode ec = 0;
741     RefPtr<Element> newElement = m_doc->createElementNS(uri, qName, ec);
742     if (!newElement) {
743         stopParsing();
744         return;
745     }
746     
747     handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec);
748     if (ec) {
749         stopParsing();
750         return;
751     }
752     
753     handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec);
754     if (ec) {
755         stopParsing();
756         return;
757     }
758
759     // FIXME: This hack ensures implicit table bodies get constructed in XHTML and XML files.
760     // We want to consolidate this with the HTML parser and HTML DOM code at some point.
761     // For now, it's too risky to rip that code up.
762     if (m_currentNode->hasTagName(tableTag) && newElement->hasTagName(trTag)) {
763         RefPtr<Node> implicitTBody = new HTMLTableSectionElement(tbodyTag, m_doc, true /* implicit */);
764         m_currentNode->addChild(implicitTBody.get());
765         setCurrentNode(implicitTBody.get());
766         if (m_view && !implicitTBody->attached())
767             implicitTBody->attach();
768     }
769
770     if (newElement->hasTagName(scriptTag))
771         static_cast<HTMLScriptElement *>(newElement.get())->setCreatedByParser(true);
772     
773     if (newElement->hasTagName(HTMLNames::scriptTag)
774 #ifdef SVG_SUPPORT
775         || newElement->hasTagName(SVGNames::scriptTag)
776 #endif
777         )
778         m_scriptStartLine = lineNumber();
779     
780     if (!m_currentNode->addChild(newElement.get())) {
781         stopParsing();
782         return;
783     }
784     
785     setCurrentNode(newElement.get());
786     if (m_view && !newElement->attached())
787         newElement->attach();
788 }
789
790 void XMLTokenizer::endElementNs()
791 {
792     if (m_parserStopped)
793         return;
794
795     if (m_parserPaused) {
796         m_pendingCallbacks->appendEndElementNSCallback();
797         return;
798     }
799     
800     exitText();
801
802     Node *n = m_currentNode;
803     while (n->implicitNode())
804         n = n->parentNode();
805     RefPtr<Node> parent = n->parentNode();
806     n->closeRenderer();
807     
808     // don't load external scripts for standalone documents (for now)
809     if (n->isElementNode() && m_view && (static_cast<Element*>(n)->hasTagName(scriptTag) 
810 #ifdef SVG_SUPPORT
811                                          || static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag)
812 #endif
813                                          )) {
814
815                                          
816         ASSERT(!m_pendingScript);
817         
818         m_requestingScript = true;
819         
820         Element* scriptElement = static_cast<Element*>(n);        
821         String scriptHref;
822         
823         if (static_cast<Element*>(n)->hasTagName(scriptTag))
824             scriptHref = scriptElement->getAttribute(srcAttr);
825 #ifdef SVG_SUPPORT
826         else if (static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag))
827             scriptHref = scriptElement->getAttribute(XLinkNames::hrefAttr);
828 #endif
829         
830         if (!scriptHref.isEmpty()) {
831             // we have a src attribute 
832             const AtomicString& charset = scriptElement->getAttribute(charsetAttr);
833             if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) {
834                 m_scriptElement = scriptElement;
835                 m_pendingScript->ref(this);
836                     
837                 // m_pendingScript will be 0 if script was already loaded and ref() executed it
838                 if (m_pendingScript)
839                     pauseParsing();
840             } else 
841                 m_scriptElement = 0;
842
843         } else {
844             String scriptCode = "";
845             for (Node *child = scriptElement->firstChild(); child; child = child->nextSibling()) {
846                 if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE)
847                     scriptCode += static_cast<CharacterData*>(child)->data();
848             }
849             m_view->frame()->loader()->executeScript(m_doc->URL(), m_scriptStartLine - 1, 0, scriptCode);
850         }
851         
852         m_requestingScript = false;
853     }
854
855     setCurrentNode(parent.get());
856 }
857
858 void XMLTokenizer::characters(const xmlChar *s, int len)
859 {
860     if (m_parserStopped)
861         return;
862     
863     if (m_parserPaused) {
864         m_pendingCallbacks->appendCharactersCallback(s, len);
865         return;
866     }
867     
868     if (m_currentNode->isTextNode() || enterText()) {
869         ExceptionCode ec = 0;
870         static_cast<Text*>(m_currentNode)->appendData(toString(s, len), ec);
871     }
872 }
873
874 bool XMLTokenizer::enterText()
875 {
876     RefPtr<Node> newNode = new Text(m_doc, "");
877     if (!m_currentNode->addChild(newNode.get()))
878         return false;
879     setCurrentNode(newNode.get());
880     return true;
881 }
882
883 void XMLTokenizer::exitText()
884 {
885     if (m_parserStopped)
886         return;
887
888     if (!m_currentNode || !m_currentNode->isTextNode())
889         return;
890
891     if (m_view && m_currentNode && !m_currentNode->attached())
892         m_currentNode->attach();
893
894     // FIXME: What's the right thing to do if the parent is really 0?
895     // Just leaving the current node set to the text node doesn't make much sense.
896     if (Node* par = m_currentNode->parentNode())
897         setCurrentNode(par);
898 }
899
900 void XMLTokenizer::handleError(ErrorType type, const char* m, int lineNumber, int columnNumber)
901 {
902     if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber && m_lastErrorColumn != columnNumber)) {
903         switch (type) {
904             case warning:
905                 m_errorMessages += String::format("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
906                 break;
907             case fatal:
908             case nonFatal:
909                 m_errorMessages += String::format("error on line %d at column %d: %s", lineNumber, columnNumber, m);
910         }
911         
912         m_lastErrorLine = lineNumber;
913         m_lastErrorColumn = columnNumber;
914         ++m_errorCount;
915     }
916     
917     if (type != warning)
918         m_sawError = true;
919     
920     if (type == fatal)
921         stopParsing();    
922 }
923
924 void XMLTokenizer::error(ErrorType type, const char *message, va_list args)
925 {
926     if (m_parserStopped)
927         return;
928
929 #if PLATFORM(WIN_OS)
930     char m[1024];
931     vsnprintf(m, sizeof(m) - 1, message, args);
932 #else
933     char *m;
934     vasprintf(&m, message, args);
935 #endif
936     
937     if (m_parserPaused)
938         m_pendingCallbacks->appendErrorCallback(type, m, lineNumber(), columnNumber());
939     else
940         handleError(type, m, lineNumber(), columnNumber());
941
942 #if !PLATFORM(WIN_OS)
943     free(m);
944 #endif
945 }
946
947 void XMLTokenizer::processingInstruction(const xmlChar *target, const xmlChar *data)
948 {
949     if (m_parserStopped)
950         return;
951
952     if (m_parserPaused) {
953         m_pendingCallbacks->appendProcessingInstructionCallback(target, data);
954         return;
955     }
956     
957     exitText();
958
959     // ### handle exceptions
960     int exception = 0;
961     RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction(
962         toString(target), toString(data), exception);
963     if (exception)
964         return;
965
966     if (!m_currentNode->addChild(pi.get()))
967         return;
968     if (m_view && !pi->attached())
969         pi->attach();
970
971     // don't load stylesheets for standalone documents
972     if (m_doc->frame()) {
973         m_sawXSLTransform = !m_sawFirstElement && !pi->checkStyleSheet();
974 #ifdef XSLT_SUPPORT
975         // Pretend we didn't see this PI if we're the result of a transform.
976         if (m_sawXSLTransform && !m_doc->transformSourceDocument())
977 #else
978         if (m_sawXSLTransform)
979 #endif
980             // Stop the SAX parser.
981             stopParsing();
982     }
983 }
984
985 void XMLTokenizer::cdataBlock(const xmlChar *s, int len)
986 {
987     if (m_parserStopped)
988         return;
989
990     if (m_parserPaused) {
991         m_pendingCallbacks->appendCDATABlockCallback(s, len);
992         return;
993     }
994     
995     exitText();
996
997     RefPtr<Node> newNode = new CDATASection(m_doc, toString(s, len));
998     if (!m_currentNode->addChild(newNode.get()))
999         return;
1000     if (m_view && !newNode->attached())
1001         newNode->attach();
1002 }
1003
1004 void XMLTokenizer::comment(const xmlChar *s)
1005 {
1006     if (m_parserStopped)
1007         return;
1008
1009     if (m_parserPaused) {
1010         m_pendingCallbacks->appendCommentCallback(s);
1011         return;
1012     }
1013     
1014     exitText();
1015
1016     RefPtr<Node> newNode = new Comment(m_doc, toString(s));
1017     m_currentNode->addChild(newNode.get());
1018     if (m_view && !newNode->attached())
1019         newNode->attach();
1020 }
1021
1022 void XMLTokenizer::internalSubset(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
1023 {
1024     if (m_parserStopped)
1025         return;
1026
1027     if (m_parserPaused) {
1028         m_pendingCallbacks->appendInternalSubsetCallback(name, externalID, systemID);
1029         return;
1030     }
1031     
1032     Document *doc = m_doc;
1033     if (!doc)
1034         return;
1035
1036     doc->setDocType(new DocumentType(doc, toString(name), toString(externalID), toString(systemID)));
1037 }
1038
1039 inline XMLTokenizer *getTokenizer(void *closure)
1040 {
1041     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1042     return static_cast<XMLTokenizer *>(ctxt->_private);
1043 }
1044
1045 // This is a hack around http://bugzilla.gnome.org/show_bug.cgi?id=159219
1046 // Otherwise libxml seems to call all the SAX callbacks twice for any replaced entity.
1047 static inline bool hackAroundLibXMLEntityBug(void *closure)
1048 {
1049     return static_cast<xmlParserCtxtPtr>(closure)->node;
1050 }
1051
1052 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)
1053 {
1054     if (hackAroundLibXMLEntityBug(closure))
1055         return;
1056
1057     getTokenizer(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1058 }
1059
1060 static void endElementNsHandler(void *closure, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
1061 {
1062     if (hackAroundLibXMLEntityBug(closure))
1063         return;
1064     
1065     getTokenizer(closure)->endElementNs();
1066 }
1067
1068 static void charactersHandler(void *closure, const xmlChar *s, int len)
1069 {
1070     if (hackAroundLibXMLEntityBug(closure))
1071         return;
1072     
1073     getTokenizer(closure)->characters(s, len);
1074 }
1075
1076 static void processingInstructionHandler(void *closure, const xmlChar *target, const xmlChar *data)
1077 {
1078     if (hackAroundLibXMLEntityBug(closure))
1079         return;
1080     
1081     getTokenizer(closure)->processingInstruction(target, data);
1082 }
1083
1084 static void cdataBlockHandler(void *closure, const xmlChar *s, int len)
1085 {
1086     if (hackAroundLibXMLEntityBug(closure))
1087         return;
1088     
1089     getTokenizer(closure)->cdataBlock(s, len);
1090 }
1091
1092 static void commentHandler(void *closure, const xmlChar *comment)
1093 {
1094     if (hackAroundLibXMLEntityBug(closure))
1095         return;
1096     
1097     getTokenizer(closure)->comment(comment);
1098 }
1099
1100 static void warningHandler(void *closure, const char *message, ...)
1101 {
1102     va_list args;
1103     va_start(args, message);
1104     getTokenizer(closure)->error(XMLTokenizer::warning, message, args);
1105     va_end(args);
1106 }
1107
1108 static void fatalErrorHandler(void *closure, const char *message, ...)
1109 {
1110     va_list args;
1111     va_start(args, message);
1112     getTokenizer(closure)->error(XMLTokenizer::fatal, message, args);
1113     va_end(args);
1114 }
1115
1116 static void normalErrorHandler(void *closure, const char *message, ...)
1117 {
1118     va_list args;
1119     va_start(args, message);
1120     getTokenizer(closure)->error(XMLTokenizer::nonFatal, message, args);
1121     va_end(args);
1122 }
1123
1124 // Using a global variable entity and marking it XML_INTERNAL_PREDEFINED_ENTITY is
1125 // a hack to avoid malloc/free. Using a global variable like this could cause trouble
1126 // if libxml implementation details were to change
1127 static xmlChar sharedXHTMLEntityResult[5] = {0,0,0,0,0};
1128 static xmlEntity sharedXHTMLEntity = {
1129     0, XML_ENTITY_DECL, 0, 0, 0, 0, 0, 0, 0, 
1130     sharedXHTMLEntityResult, sharedXHTMLEntityResult, 0,
1131     XML_INTERNAL_PREDEFINED_ENTITY, 0, 0, 0, 0, 0
1132 };
1133
1134 static xmlEntityPtr getXHTMLEntity(const xmlChar* name)
1135 {
1136     UChar c = decodeNamedEntity(reinterpret_cast<const char*>(name));
1137     if (!c)
1138         return 0;
1139
1140     CString value = String(&c, 1).utf8();
1141     assert(value.length() < 5);
1142     sharedXHTMLEntity.length = value.length();
1143     sharedXHTMLEntity.name = name;
1144     memcpy(sharedXHTMLEntityResult, value.data(), sharedXHTMLEntity.length + 1);
1145
1146     return &sharedXHTMLEntity;
1147 }
1148
1149 static xmlEntityPtr getEntityHandler(void *closure, const xmlChar *name)
1150 {
1151     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1152     xmlEntityPtr ent = xmlGetPredefinedEntity(name);
1153     if (ent)
1154         return ent;
1155
1156     ent = xmlGetDocEntity(ctxt->myDoc, name);
1157     if (!ent && getTokenizer(closure)->isXHTMLDocument())
1158         ent = getXHTMLEntity(name);
1159     
1160     return ent;
1161 }
1162
1163 static void internalSubsetHandler(void *closure, const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
1164 {
1165     getTokenizer(closure)->internalSubset(name, externalID, systemID);
1166     xmlSAX2InternalSubset(closure, name, externalID, systemID);
1167 }
1168
1169 static void externalSubsetHandler(void *closure, const xmlChar *name, const xmlChar *externalId, const xmlChar *systemId)
1170 {
1171     String extId = toString(externalId);
1172     if ((extId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
1173         || (extId == "-//W3C//DTD XHTML 1.1//EN")
1174         || (extId == "-//W3C//DTD XHTML 1.0 Strict//EN")
1175         || (extId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
1176         || (extId == "-//W3C//DTD XHTML Basic 1.0//EN")
1177         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
1178         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
1179         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
1180         getTokenizer(closure)->setIsXHTMLDocument(true); // controls if we replace entities or not.
1181 }
1182
1183 static void ignorableWhitespaceHandler(void *ctx, const xmlChar *ch, int len)
1184 {
1185     // nothing to do, but we need this to work around a crasher
1186     // http://bugzilla.gnome.org/show_bug.cgi?id=172255
1187     // http://bugs.webkit.org/show_bug.cgi?id=5792
1188 }
1189
1190 void XMLTokenizer::initializeParserContext()
1191 {
1192     xmlSAXHandler sax;
1193     memset(&sax, 0, sizeof(sax));
1194     sax.error = normalErrorHandler;
1195     sax.fatalError = fatalErrorHandler;
1196     sax.characters = charactersHandler;
1197     sax.processingInstruction = processingInstructionHandler;
1198     sax.cdataBlock = cdataBlockHandler;
1199     sax.comment = commentHandler;
1200     sax.warning = warningHandler;
1201     sax.startElementNs = startElementNsHandler;
1202     sax.endElementNs = endElementNsHandler;
1203     sax.getEntity = getEntityHandler;
1204     sax.startDocument = xmlSAX2StartDocument;
1205     sax.internalSubset = internalSubsetHandler;
1206     sax.externalSubset = externalSubsetHandler;
1207     sax.ignorableWhitespace = ignorableWhitespaceHandler;
1208     sax.entityDecl = xmlSAX2EntityDecl;
1209     sax.initialized = XML_SAX2_MAGIC;
1210     
1211     m_parserStopped = false;
1212     m_sawError = false;
1213     m_sawXSLTransform = false;
1214     m_sawFirstElement = false;
1215     m_context = createStringParser(&sax, this);
1216 }
1217
1218 void XMLTokenizer::end()
1219 {
1220 #ifdef XSLT_SUPPORT
1221     if (m_sawXSLTransform) {
1222         m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->URL()));
1223         
1224         m_doc->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
1225         m_doc->updateStyleSelector();
1226         m_doc->setParsing(true);
1227         m_parserStopped = true;
1228     }
1229 #endif
1230
1231     if (m_context) {
1232         // Tell libxml we're done.
1233         xmlParseChunk(m_context, 0, 0, 1);
1234         
1235         if (m_context->myDoc)
1236             xmlFreeDoc(m_context->myDoc);
1237         xmlFreeParserCtxt(m_context);
1238         m_context = 0;
1239     }
1240     
1241     if (m_sawError)
1242         insertErrorMessageBlock();
1243     else {
1244         exitText();
1245         m_doc->updateStyleSelector();
1246     }
1247     
1248     setCurrentNode(0);
1249     m_doc->finishedParsing();    
1250 }
1251
1252 void XMLTokenizer::finish()
1253 {
1254     if (m_parserPaused)
1255         m_finishCalled = true;
1256     else
1257         end();
1258 }
1259
1260 static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages) 
1261 {
1262     ExceptionCode ec = 0;
1263     RefPtr<Element> reportElement = doc->createElementNS(xhtmlNamespaceURI, "parsererror", ec);
1264     reportElement->setAttribute(styleAttr, "white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
1265     
1266     RefPtr<Element> h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1267     reportElement->appendChild(h3.get(), ec);
1268     h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
1269     
1270     RefPtr<Element> fixed = doc->createElementNS(xhtmlNamespaceURI, "div", ec);
1271     reportElement->appendChild(fixed.get(), ec);
1272     fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px");
1273     fixed->appendChild(doc->createTextNode(errorMessages), ec);
1274     
1275     h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1276     reportElement->appendChild(h3.get(), ec);
1277     h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
1278     
1279     return reportElement;
1280 }
1281
1282 void XMLTokenizer::insertErrorMessageBlock()
1283 {
1284     // One or more errors occurred during parsing of the code. Display an error block to the user above
1285     // the normal content (the DOM tree is created manually and includes line/col info regarding 
1286     // where the errors are located)
1287
1288     // Create elements for display
1289     ExceptionCode ec = 0;
1290     Document *doc = m_doc;
1291     Node* documentElement = doc->documentElement();
1292     if (!documentElement) {
1293         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1294         doc->appendChild(rootElement, ec);
1295         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1296         rootElement->appendChild(body, ec);
1297         documentElement = body.get();
1298     }
1299 #ifdef SVG_SUPPORT
1300     else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
1301         // Until our SVG implementation has text support, it is best if we 
1302         // wrap the erroneous SVG document in an xhtml document and render
1303         // the combined document with error messages.
1304         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1305         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1306         rootElement->appendChild(body, ec);
1307         body->appendChild(documentElement, ec);
1308         doc->appendChild(rootElement.get(), ec);
1309         documentElement = body.get();
1310     }
1311 #endif
1312
1313     RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
1314     documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
1315 #ifdef XSLT_SUPPORT
1316     if (doc->transformSourceDocument()) {
1317         RefPtr<Element> par = doc->createElementNS(xhtmlNamespaceURI, "p", ec);
1318         reportElement->appendChild(par, ec);
1319         par->setAttribute(styleAttr, "white-space: normal");
1320         par->appendChild(doc->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."), ec);
1321     }
1322 #endif
1323     doc->updateRendering();
1324 }
1325
1326 void XMLTokenizer::notifyFinished(CachedResource *finishedObj)
1327 {
1328     ASSERT(m_pendingScript == finishedObj);
1329     ASSERT(m_pendingScript->accessCount() > 0);
1330         
1331     String cachedScriptUrl = m_pendingScript->url();
1332     String scriptSource = m_pendingScript->script();
1333     bool errorOccurred = m_pendingScript->errorOccurred();
1334     m_pendingScript->deref(this);
1335     m_pendingScript = 0;
1336     
1337     RefPtr<Element> e = m_scriptElement;
1338     m_scriptElement = 0;
1339     
1340     if (errorOccurred) 
1341         EventTargetNodeCast(e.get())->dispatchHTMLEvent(errorEvent, true, false);
1342     else {
1343         m_view->frame()->loader()->executeScript(cachedScriptUrl, 0, 0, scriptSource);
1344         EventTargetNodeCast(e.get())->dispatchHTMLEvent(loadEvent, false, false);
1345     }
1346     
1347     m_scriptElement = 0;
1348     
1349     if (!m_requestingScript)
1350         resumeParsing();
1351 }
1352
1353 bool XMLTokenizer::isWaitingForScripts() const
1354 {
1355     return m_pendingScript != 0;
1356 }
1357
1358 #ifdef XSLT_SUPPORT
1359 void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const DeprecatedString &url)
1360 {
1361     if (source.isEmpty())
1362         return 0;
1363
1364     // Parse in a single chunk into an xmlDocPtr
1365     // FIXME: Hook up error handlers so that a failure to parse the main document results in
1366     // good error messages.
1367     const UChar BOM = 0xFEFF;
1368     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
1369
1370     xmlGenericErrorFunc oldErrorFunc = xmlGenericError;
1371     void* oldErrorContext = xmlGenericErrorContext;
1372     
1373     setLoaderForLibXMLCallbacks(docLoader);        
1374     xmlSetGenericErrorFunc(0, errorFunc);
1375     
1376     xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char*>(source.characters()),
1377                                         source.length() * sizeof(UChar),
1378                                         url.ascii(),
1379                                         BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", 
1380                                         XSLT_PARSE_OPTIONS);
1381     
1382     setLoaderForLibXMLCallbacks(0);
1383     xmlSetGenericErrorFunc(oldErrorContext, oldErrorFunc);
1384     
1385     return sourceDoc;
1386 }
1387 #endif
1388
1389 Tokenizer *newXMLTokenizer(Document *d, FrameView *v)
1390 {
1391     return new XMLTokenizer(d, v);
1392 }
1393
1394 int XMLTokenizer::lineNumber() const
1395 {
1396     return m_context->input->line;
1397 }
1398
1399 int XMLTokenizer::columnNumber() const
1400 {
1401     return m_context->input->col;
1402 }
1403
1404 void XMLTokenizer::stopParsing()
1405 {
1406     Tokenizer::stopParsing();
1407     xmlStopParser(m_context);
1408 }
1409
1410 void XMLTokenizer::pauseParsing()
1411 {
1412     if (m_parsingFragment)
1413         return;
1414     
1415     m_parserPaused = true;
1416 }
1417
1418 void XMLTokenizer::resumeParsing()
1419 {
1420     ASSERT(m_parserPaused);
1421     
1422     m_parserPaused = false;
1423     
1424     // First, execute any pending callbacks
1425     while (!m_pendingCallbacks->isEmpty()) {
1426         m_pendingCallbacks->callAndRemoveFirstCallback(this);
1427         
1428         // A callback paused the parser
1429         if (m_parserPaused)
1430             return;
1431     }
1432     
1433     // Then, write any pending data
1434     SegmentedString rest = m_pendingSrc;
1435     m_pendingSrc.clear();
1436     write(rest, false);
1437
1438     // Finally, if finish() has been called and write() didn't result
1439     // in any further callbacks being queued, call end()
1440     if (m_finishCalled && m_pendingCallbacks->isEmpty())
1441         end();
1442 }
1443
1444 static void balancedStartElementNsHandler(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)
1445 {
1446    static_cast<XMLTokenizer *>(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1447 }
1448
1449 static void balancedEndElementNsHandler(void *closure, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
1450 {
1451     static_cast<XMLTokenizer *>(closure)->endElementNs();
1452 }
1453
1454 static void balancedCharactersHandler(void *closure, const xmlChar *s, int len)
1455 {
1456     static_cast<XMLTokenizer *>(closure)->characters(s, len);
1457 }
1458
1459 static void balancedProcessingInstructionHandler(void *closure, const xmlChar *target, const xmlChar *data)
1460 {
1461     static_cast<XMLTokenizer *>(closure)->processingInstruction(target, data);
1462 }
1463
1464 static void balancedCdataBlockHandler(void *closure, const xmlChar *s, int len)
1465 {
1466     static_cast<XMLTokenizer *>(closure)->cdataBlock(s, len);
1467 }
1468
1469 static void balancedCommentHandler(void *closure, const xmlChar *comment)
1470 {
1471     static_cast<XMLTokenizer *>(closure)->comment(comment);
1472 }
1473
1474 static void balancedWarningHandler(void *closure, const char *message, ...)
1475 {
1476     va_list args;
1477     va_start(args, message);
1478     static_cast<XMLTokenizer *>(closure)->error(XMLTokenizer::warning, message, args);
1479     va_end(args);
1480 }
1481
1482 bool parseXMLDocumentFragment(const String &string, DocumentFragment *fragment, Element *parent)
1483 {
1484     XMLTokenizer tokenizer(fragment, parent);
1485     
1486     xmlSAXHandler sax;
1487     memset(&sax, 0, sizeof(sax));
1488
1489     sax.characters = balancedCharactersHandler;
1490     sax.processingInstruction = balancedProcessingInstructionHandler;
1491     sax.startElementNs = balancedStartElementNsHandler;
1492     sax.endElementNs = balancedEndElementNsHandler;
1493     sax.cdataBlock = balancedCdataBlockHandler;
1494     sax.ignorableWhitespace = balancedCdataBlockHandler;
1495     sax.comment = balancedCommentHandler;
1496     sax.warning = balancedWarningHandler;
1497     sax.initialized = XML_SAX2_MAGIC;
1498     
1499     int result = xmlParseBalancedChunkMemory(0, &sax, &tokenizer, 0, (const xmlChar*)(const char*)(string.utf8()), 0);
1500     return result == 0;
1501 }
1502
1503 // --------------------------------
1504
1505 struct AttributeParseState {
1506     HashMap<String, String> attributes;
1507     bool gotAttributes;
1508 };
1509
1510
1511 static void attributesStartElementNsHandler(void *closure, const xmlChar *xmlLocalName, const xmlChar *xmlPrefix, const xmlChar *xmlURI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **libxmlAttributes)
1512 {
1513     if (strcmp(reinterpret_cast<const char *>(xmlLocalName), "attrs") != 0)
1514         return;
1515     
1516     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1517     AttributeParseState *state = static_cast<AttributeParseState *>(ctxt->_private);
1518     
1519     state->gotAttributes = true;
1520     
1521     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
1522     for(int i = 0; i < nb_attributes; i++) {
1523         String attrLocalName = toString(attributes[i].localname);
1524         int valueLength = (int) (attributes[i].end - attributes[i].value);
1525         String attrValue = toString(attributes[i].value, valueLength);
1526         String attrPrefix = toString(attributes[i].prefix);
1527         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
1528         
1529         state->attributes.set(attrQName, attrValue);
1530     }
1531 }
1532
1533 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
1534 {
1535     AttributeParseState state;
1536     state.gotAttributes = false;
1537
1538     xmlSAXHandler sax;
1539     memset(&sax, 0, sizeof(sax));
1540     sax.startElementNs = attributesStartElementNsHandler;
1541     sax.initialized = XML_SAX2_MAGIC;
1542     xmlParserCtxtPtr parser = createStringParser(&sax, &state);
1543     String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
1544     xmlParseChunk(parser, reinterpret_cast<const char*>(parseString.characters()), parseString.length() * sizeof(UChar), 1);
1545     if (parser->myDoc)
1546         xmlFreeDoc(parser->myDoc);
1547     xmlFreeParserCtxt(parser);
1548
1549     attrsOK = state.gotAttributes;
1550     return state.attributes;
1551 }
1552
1553 }