Reviewed by Eric.
[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 "Cache.h"
29 #include "CachedScript.h"
30 #include "Comment.h"
31 #include "DocLoader.h"
32 #include "Document.h"
33 #include "DocumentFragment.h"
34 #include "DocumentType.h"
35 #include "EventNames.h"
36 #include "Frame.h"
37 #include "HTMLNames.h"
38 #include "HTMLScriptElement.h"
39 #include "HTMLTableSectionElement.h"
40 #include "HTMLTokenizer.h"
41 #include "LoaderFunctions.h"
42 #include "ProcessingInstruction.h"
43 #include "ResourceLoader.h"
44 #include <libxml/parser.h>
45 #include <libxml/parserInternals.h>
46 #include <wtf/Platform.h>
47 #include <wtf/Vector.h>
48
49 #ifdef KHTML_XSLT
50 #include <libxslt/xslt.h>
51 #endif
52
53 #ifdef SVG_SUPPORT
54 #include "SVGNames.h"
55 #include "XLinkNames.h"
56 #endif
57
58 using namespace std;
59
60 namespace WebCore {
61
62 using namespace EventNames;
63 using namespace HTMLNames;
64
65 const int maxErrors = 25;
66
67 typedef HashMap<StringImpl*, StringImpl*> PrefixForNamespaceMap;
68
69 class PendingCallbacks;
70
71 class XMLTokenizer : public Tokenizer, public CachedResourceClient {
72 public:
73     XMLTokenizer(Document *, FrameView * = 0);
74     XMLTokenizer(DocumentFragment *, Element *);
75     ~XMLTokenizer();
76
77     enum ErrorType { warning, nonFatal, fatal };
78
79     // from Tokenizer
80     virtual bool write(const SegmentedString &str, bool);
81     virtual void finish();
82     virtual bool isWaitingForScripts() const;
83     virtual void stopParsing();
84
85     void end();
86
87     void pauseParsing();
88     void resumeParsing();
89     
90     void setIsXHTMLDocument(bool isXHTML) { m_isXHTMLDocument = isXHTML; }
91     bool isXHTMLDocument() const { return m_isXHTMLDocument; }
92
93     // from CachedResourceClient
94     virtual void notifyFinished(CachedResource *finishedObj);
95
96     // callbacks from parser SAX
97     void error(ErrorType, const char *message, va_list args);
98     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);
99     void endElementNs();
100     void characters(const xmlChar *s, int len);
101     void processingInstruction(const xmlChar *target, const xmlChar *data);
102     void cdataBlock(const xmlChar *s, int len);
103     void comment(const xmlChar *s);
104     void internalSubset(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID);
105
106     void handleError(ErrorType type, const char* m, int lineNumber, int columnNumber);
107     
108 private:
109     void initializeParserContext();
110     void setCurrentNode(Node*);
111
112     int lineNumber() const;
113     int columnNumber() const;
114
115     void insertErrorMessageBlock();
116
117     bool enterText();
118     void exitText();
119
120     Document *m_doc;
121     FrameView *m_view;
122     
123     DeprecatedString m_originalSourceForTransform;
124
125     xmlParserCtxtPtr m_context;
126     Node *m_currentNode;
127     bool m_currentNodeIsReferenced;
128
129     bool m_sawError;
130     bool m_sawXSLTransform;
131     bool m_sawFirstElement;
132     bool m_isXHTMLDocument;
133     
134     bool m_parserPaused;
135     bool m_requestingScript;
136     bool m_finishCalled;
137     
138     int m_errorCount;
139     int m_lastErrorLine;
140     int m_lastErrorColumn;
141     String m_errorMessages;
142
143     CachedScript *m_pendingScript;
144     RefPtr<Element> m_scriptElement;
145     
146     bool m_parsingFragment;
147     String m_defaultNamespaceURI;
148     PrefixForNamespaceMap m_prefixToNamespaceMap;
149     
150     PendingCallbacks* m_pendingCallbacks;
151     SegmentedString m_pendingSrc;
152 };
153
154 class PendingCallbacks {
155 public:
156     PendingCallbacks()
157     {
158         m_callbacks.setAutoDelete(true);
159     }
160     
161     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)
162     {
163         PendingStartElementNSCallback* callback = new PendingStartElementNSCallback;
164         
165         callback->xmlLocalName = xmlStrdup(xmlLocalName);
166         callback->xmlPrefix = xmlStrdup(xmlPrefix);
167         callback->xmlURI = xmlStrdup(xmlURI);
168         callback->nb_namespaces = nb_namespaces;
169         callback->namespaces = reinterpret_cast<xmlChar**>(xmlMalloc(sizeof (xmlChar*) * nb_namespaces * 2));
170         for (int i = 0; i < nb_namespaces * 2 ; i++)
171             callback->namespaces[i] = xmlStrdup(namespaces[i]);
172         callback->nb_attributes = nb_attributes;
173         callback->nb_defaulted = nb_defaulted;
174         callback->attributes =  reinterpret_cast<xmlChar**>(xmlMalloc(sizeof (xmlChar*) * nb_attributes * 5));
175         for (int i = 0; i < nb_attributes; i++) {
176             // Each attribute has 5 elements in the array:
177             // name, prefix, uri, value and an end pointer.
178             
179             for (int j = 0; j < 3; j++)
180                 callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]);
181             
182             int len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
183
184             callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len);
185             callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len;
186         }
187         
188         m_callbacks.append(callback);
189     }
190
191     void appendEndElementNSCallback()
192     {
193         PendingEndElementNSCallback* callback = new PendingEndElementNSCallback;
194         
195         m_callbacks.append(callback);
196     }
197     
198     void appendCharactersCallback(const xmlChar *s, int len)
199     {
200         PendingCharactersCallback* callback = new PendingCharactersCallback;
201         
202         callback->s = xmlStrndup(s, len);
203         callback->len = len;
204         
205         m_callbacks.append(callback);        
206     }
207     
208     void appendProcessingInstructionCallback(const xmlChar *target, const xmlChar *data)
209     {
210         PendingProcessingInstructionCallback* callback = new PendingProcessingInstructionCallback;
211         
212         callback->target = xmlStrdup(target);
213         callback->data = xmlStrdup(data);
214         
215         m_callbacks.append(callback);
216     }
217     
218     void appendCDATABlockCallback(const xmlChar *s, int len)
219     {
220         PendingCDATABlockCallback* callback = new PendingCDATABlockCallback;
221         
222         callback->s = xmlStrndup(s, len);
223         callback->len = len;
224         
225         m_callbacks.append(callback);        
226     }
227
228     void appendCommentCallback(const xmlChar *s)
229     {
230         PendingCommentCallback* callback = new PendingCommentCallback;
231         
232         callback->s = xmlStrdup(s);
233         
234         m_callbacks.append(callback);        
235     }
236
237     void appendInternalSubsetCallback(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
238     {
239         PendingInternalSubsetCallback* callback = new PendingInternalSubsetCallback;
240         
241         callback->name = xmlStrdup(name);
242         callback->externalID = xmlStrdup(externalID);
243         callback->systemID = xmlStrdup(systemID);
244         
245         m_callbacks.append(callback);        
246     }
247     
248     void appendErrorCallback(XMLTokenizer::ErrorType type, const char* message, int lineNumber, int columnNumber)
249     {
250         PendingErrorCallback* callback = new PendingErrorCallback;
251         
252         callback->message = strdup(message);
253         callback->type = type;
254         callback->lineNumber = lineNumber;
255         callback->columnNumber = columnNumber;
256         
257         m_callbacks.append(callback);
258     }
259
260     void callAndRemoveFirstCallback(XMLTokenizer* tokenizer)
261     {
262         PendingCallback *cb = m_callbacks.getFirst();
263             
264         cb->call(tokenizer);
265         m_callbacks.removeFirst();
266     }
267     
268     bool isEmpty() const { return m_callbacks.isEmpty(); }
269     
270 private:    
271     struct PendingCallback {        
272         
273         virtual ~PendingCallback() { } 
274
275         virtual void call(XMLTokenizer* tokenizer) = 0;
276     };  
277     
278     struct PendingStartElementNSCallback : public PendingCallback {        
279         virtual ~PendingStartElementNSCallback() {
280             xmlFree(xmlLocalName);
281             xmlFree(xmlPrefix);
282             xmlFree(xmlURI);
283             for (int i = 0; i < nb_namespaces * 2; i++)
284                 xmlFree(namespaces[i]);
285             xmlFree(namespaces);
286             for (int i = 0; i < nb_attributes; i++)
287                 for (int j = 0; j < 4; j++) 
288                     xmlFree(attributes[i * 5 + j]);
289             xmlFree(attributes);
290         }
291         
292         virtual void call(XMLTokenizer* tokenizer) {
293             tokenizer->startElementNs(xmlLocalName, xmlPrefix, xmlURI, 
294                                       nb_namespaces, (const xmlChar**)namespaces,
295                                       nb_attributes, nb_defaulted, (const xmlChar**)(attributes));
296         }
297
298         xmlChar* xmlLocalName;
299         xmlChar* xmlPrefix;
300         xmlChar* xmlURI;
301         int nb_namespaces;
302         xmlChar** namespaces;
303         int nb_attributes;
304         int nb_defaulted;
305         xmlChar** attributes;
306     };
307     
308     struct PendingEndElementNSCallback : public PendingCallback {
309         virtual void call(XMLTokenizer* tokenizer) 
310         {
311             tokenizer->endElementNs();
312         }
313     };
314     
315     struct PendingCharactersCallback : public PendingCallback {
316         virtual ~PendingCharactersCallback() 
317         {
318             xmlFree(s);
319         }
320     
321         virtual void call(XMLTokenizer* tokenizer) 
322         {
323             tokenizer->characters(s, len);
324         }
325         
326         xmlChar* s;
327         int len;
328     };
329
330     struct PendingProcessingInstructionCallback : public PendingCallback {
331         virtual ~PendingProcessingInstructionCallback() 
332         {
333             xmlFree(target);
334             xmlFree(data);
335         }
336         
337         virtual void call(XMLTokenizer* tokenizer) 
338         {
339             tokenizer->processingInstruction(target, data);
340         }
341         
342         xmlChar* target;
343         xmlChar* data;
344     };
345     
346     struct PendingCDATABlockCallback : public PendingCallback {
347         virtual ~PendingCDATABlockCallback() 
348         {
349             xmlFree(s);
350         }
351         
352         virtual void call(XMLTokenizer* tokenizer) 
353         {
354             tokenizer->cdataBlock(s, len);
355         }
356         
357         xmlChar* s;
358         int len;
359     };
360
361     struct PendingCommentCallback : public PendingCallback {
362         virtual ~PendingCommentCallback() 
363         {
364             xmlFree(s);
365         }
366         
367         virtual void call(XMLTokenizer* tokenizer) 
368         {
369             tokenizer->comment(s);
370         }
371
372         xmlChar* s;
373     };
374     
375     struct PendingInternalSubsetCallback : public PendingCallback {
376         virtual ~PendingInternalSubsetCallback() 
377         {
378             xmlFree(name);
379             xmlFree(externalID);
380             xmlFree(systemID);
381         }
382         
383         virtual void call(XMLTokenizer* tokenizer)
384         {
385             tokenizer->internalSubset(name, externalID, systemID);
386         }
387         
388         xmlChar* name;
389         xmlChar* externalID;
390         xmlChar* systemID;        
391     };
392     
393     struct PendingErrorCallback: public PendingCallback {
394         virtual ~PendingErrorCallback() 
395         {
396             free (message);
397         }
398         
399         virtual void call(XMLTokenizer* tokenizer) 
400         {
401             tokenizer->handleError(type, message, lineNumber, columnNumber);
402         }
403         
404         XMLTokenizer::ErrorType type;
405         char* message;
406         int lineNumber;
407         int columnNumber;
408     };
409     
410 public:
411     DeprecatedPtrList<PendingCallback> m_callbacks;
412 };
413
414 // --------------------------------
415
416 static int globalDescriptor = 0;
417
418 static int matchFunc(const char* uri)
419 {
420     return 1; // Match everything.
421 }
422
423 static DocLoader *globalDocLoader = 0;
424
425 class OffsetBuffer {
426 public:
427     OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { }
428     
429     int readOutBytes(char *outputBuffer, unsigned askedToRead) {
430         unsigned bytesLeft = m_buffer.size() - m_currentOffset;
431         unsigned lenToCopy = min(askedToRead, bytesLeft);
432         if (lenToCopy) {
433             memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy);
434             m_currentOffset += lenToCopy;
435         }
436         return lenToCopy;
437     }
438
439 private:
440     Vector<char> m_buffer;
441     unsigned m_currentOffset;
442 };
443
444 static bool shouldAllowExternalLoad(const char* inURI)
445 {
446     DeprecatedString url(inURI);
447
448     if (url.contains("/etc/xml/catalog")
449         || url.startsWith("http://www.w3.org/Graphics/SVG")
450         || url.startsWith("http://www.w3.org/TR/xhtml"))
451         return false;
452     return true;
453 }
454
455 static void* openFunc(const char* uri)
456 {
457     if (!globalDocLoader || !shouldAllowExternalLoad(uri))
458         return &globalDescriptor;
459
460     KURL finalURL;
461     ResourceLoader* job = new ResourceLoader(0, "GET", uri);
462     DeprecatedString headers;
463     Vector<char> data = ServeSynchronousRequest(Cache::loader(), globalDocLoader, job, finalURL, headers);
464     
465     return new OffsetBuffer(data);
466 }
467
468 static int readFunc(void* context, char* buffer, int len)
469 {
470     // Do 0-byte reads in case of a null descriptor
471     if (context == &globalDescriptor)
472         return 0;
473         
474     OffsetBuffer *data = static_cast<OffsetBuffer *>(context);
475     return data->readOutBytes(buffer, len);
476 }
477
478 static int writeFunc(void* context, const char* buffer, int len)
479 {
480     // Always just do 0-byte writes
481     return 0;
482 }
483
484 static int closeFunc(void * context)
485 {
486     if (context != &globalDescriptor) {
487         OffsetBuffer *data = static_cast<OffsetBuffer *>(context);
488         delete data;
489     }
490     return 0;
491 }
492
493 static void errorFunc(void*, const char*, ...)
494 {
495     // FIXME: It would be nice to display error messages somewhere.
496 }
497
498 void setLoaderForLibXMLCallbacks(DocLoader *docLoader)
499 {
500     globalDocLoader = docLoader;
501 }
502
503 static xmlParserCtxtPtr createQStringParser(xmlSAXHandlerPtr handlers, void *userData)
504 {
505     static bool didInit = false;
506     if (!didInit) {
507         xmlInitParser();
508         xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
509         xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
510         didInit = true;
511     }
512
513     xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0);
514     parser->_private = userData;
515     parser->replaceEntities = true;
516     const DeprecatedChar BOM(0xFEFF);
517     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
518     xmlSwitchEncoding(parser, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
519     return parser;
520 }
521
522 // --------------------------------
523
524 XMLTokenizer::XMLTokenizer(Document *_doc, FrameView *_view)
525     : m_doc(_doc)
526     , m_view(_view)
527     , m_context(0)
528     , m_currentNode(_doc)
529     , m_currentNodeIsReferenced(false)
530     , m_sawError(false)
531     , m_sawXSLTransform(false)
532     , m_sawFirstElement(false)
533     , m_isXHTMLDocument(false)
534     , m_parserPaused(false)
535     , m_requestingScript(false)
536     , m_finishCalled(false)
537     , m_errorCount(0)
538     , m_lastErrorLine(0)
539     , m_lastErrorColumn(0)
540     , m_pendingScript(0)
541     , m_parsingFragment(false)
542     , m_pendingCallbacks(new PendingCallbacks)
543 {
544 }
545
546 XMLTokenizer::XMLTokenizer(DocumentFragment *fragment, Element *parentElement)
547     : m_doc(fragment->document())
548     , m_view(0)
549     , m_context(0)
550     , m_currentNode(fragment)
551     , m_currentNodeIsReferenced(fragment)
552     , m_sawError(false)
553     , m_sawXSLTransform(false)
554     , m_sawFirstElement(false)
555     , m_isXHTMLDocument(false)
556     , m_parserPaused(false)
557     , m_requestingScript(false)
558     , m_finishCalled(false)
559     , m_errorCount(0)
560     , m_lastErrorLine(0)
561     , m_lastErrorColumn(0)
562     , m_pendingScript(0)
563     , m_parsingFragment(true)
564     , m_pendingCallbacks(new PendingCallbacks)
565 {
566     if (fragment)
567         fragment->ref();
568     if (m_doc)
569         m_doc->ref();
570           
571     // Add namespaces based on the parent node
572     Vector<Element*> elemStack;
573     while (parentElement) {
574         elemStack.append(parentElement);
575         
576         Node *n = parentElement->parentNode();
577         if (!n || !n->isElementNode())
578             break;
579         parentElement = static_cast<Element *>(n);
580     }
581     
582     if (elemStack.isEmpty())
583         return;
584     
585     for (Element *element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
586         if (NamedAttrMap *attrs = element->attributes()) {
587             for (unsigned i = 0; i < attrs->length(); i++) {
588                 Attribute *attr = attrs->attributeItem(i);
589                 if (attr->localName() == "xmlns")
590                     m_defaultNamespaceURI = attr->value();
591                 else if (attr->prefix() == "xmlns")
592                     m_prefixToNamespaceMap.set(attr->localName().impl(), attr->value().impl());
593             }
594         }
595     }
596 }
597
598 XMLTokenizer::~XMLTokenizer()
599 {
600     setCurrentNode(0);
601     if (m_parsingFragment && m_doc)
602         m_doc->deref();
603     delete m_pendingCallbacks;
604     if (m_pendingScript)
605         m_pendingScript->deref(this);
606 }
607
608 void XMLTokenizer::setCurrentNode(Node* n)
609 {
610     bool nodeNeedsReference = n && n != m_doc;
611     if (nodeNeedsReference)
612         n->ref(); 
613     if (m_currentNodeIsReferenced) 
614         m_currentNode->deref(); 
615     m_currentNode = n;
616     m_currentNodeIsReferenced = nodeNeedsReference;
617 }
618
619 bool XMLTokenizer::write(const SegmentedString &s, bool /*appendData*/ )
620 {
621     DeprecatedString parseString = s.toString();
622     
623     if (m_sawXSLTransform || !m_sawFirstElement)
624         m_originalSourceForTransform += parseString;
625
626     if (m_parserStopped || m_sawXSLTransform)
627         return false;
628     
629     if (m_parserPaused) {
630         m_pendingSrc.append(s);
631         return false;
632     }
633     
634     if (!m_context)
635         initializeParserContext();
636     
637     // libXML throws an error if you try to switch the encoding for an empty string.
638     if (parseString.length()) {
639         // Hack around libxml2's lack of encoding overide support by manually
640         // resetting the encoding to UTF-16 before every chunk.  Otherwise libxml
641         // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks 
642         // and switch encodings, causing the parse to fail.
643         const DeprecatedChar BOM(0xFEFF);
644         const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
645         xmlSwitchEncoding(m_context, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
646         
647         xmlParseChunk(m_context, reinterpret_cast<const char *>(parseString.unicode()), sizeof(DeprecatedChar) * parseString.length(), 0);
648     }
649     
650     return false;
651 }
652
653 inline DeprecatedString toQString(const xmlChar *str, unsigned int len)
654 {
655     return DeprecatedString::fromUtf8(reinterpret_cast<const char *>(str), len);
656 }
657
658 inline DeprecatedString toQString(const xmlChar *str)
659 {
660     return DeprecatedString::fromUtf8(str ? reinterpret_cast<const char *>(str) : "");
661 }
662
663 inline String toString(const xmlChar* str, unsigned int len)
664 {
665     return DeprecatedString::fromUtf8(reinterpret_cast<const char *>(str), len);
666 }
667
668 inline String toString(const xmlChar* str)
669 {
670     return DeprecatedString::fromUtf8(str ? reinterpret_cast<const char *>(str) : "");
671 }
672
673 struct _xmlSAX2Namespace {
674     const xmlChar *prefix;
675     const xmlChar *uri;
676 };
677 typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
678
679 static inline void handleElementNamespaces(Element *newElement, const xmlChar **libxmlNamespaces, int nb_namespaces, ExceptionCode& ec)
680 {
681     xmlSAX2Namespace *namespaces = reinterpret_cast<xmlSAX2Namespace *>(libxmlNamespaces);
682     for(int i = 0; i < nb_namespaces; i++) {
683         String namespaceQName = "xmlns";
684         String namespaceURI = toString(namespaces[i].uri);
685         if (namespaces[i].prefix)
686             namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
687         newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
688         if (ec) // exception setting attributes
689             return;
690     }
691 }
692
693 struct _xmlSAX2Attributes {
694     const xmlChar *localname;
695     const xmlChar *prefix;
696     const xmlChar *uri;
697     const xmlChar *value;
698     const xmlChar *end;
699 };
700 typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
701
702 static inline void handleElementAttributes(Element *newElement, const xmlChar **libxmlAttributes, int nb_attributes, ExceptionCode& ec)
703 {
704     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
705     for(int i = 0; i < nb_attributes; i++) {
706         String attrLocalName = toQString(attributes[i].localname);
707         int valueLength = (int) (attributes[i].end - attributes[i].value);
708         String attrValue = toQString(attributes[i].value, valueLength);
709         String attrPrefix = toQString(attributes[i].prefix);
710         String attrURI = attrPrefix.isEmpty() ? String() : toQString(attributes[i].uri);
711         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
712         
713         newElement->setAttributeNS(attrURI, attrQName, attrValue, ec);
714         if (ec) // exception setting attributes
715             return;
716     }
717 }
718
719 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)
720 {
721     if (m_parserStopped)
722         return;
723     
724     if (m_parserPaused) {        
725         m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, nb_attributes, nb_defaulted, libxmlAttributes);
726         return;
727     }
728     
729     m_sawFirstElement = true;
730
731     exitText();
732
733     String localName = toQString(xmlLocalName);
734     String uri = toQString(xmlURI);
735     String prefix = toQString(xmlPrefix);
736     String qName = prefix.isEmpty() ? localName : prefix + ":" + localName;
737     
738     if (m_parsingFragment && uri.isEmpty()) {
739         if (!prefix.isEmpty())
740             uri = String(m_prefixToNamespaceMap.get(prefix.impl()));
741         else
742             uri = m_defaultNamespaceURI;
743     }
744
745     ExceptionCode ec = 0;
746     RefPtr<Element> newElement = m_doc->createElementNS(uri, qName, ec);
747     if (!newElement) {
748         stopParsing();
749         return;
750     }
751     
752     handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec);
753     if (ec) {
754         stopParsing();
755         return;
756     }
757     
758     handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec);
759     if (ec) {
760         stopParsing();
761         return;
762     }
763
764     // FIXME: This hack ensures implicit table bodies get constructed in XHTML and XML files.
765     // We want to consolidate this with the HTML parser and HTML DOM code at some point.
766     // For now, it's too risky to rip that code up.
767     if (m_currentNode->hasTagName(tableTag) && newElement->hasTagName(trTag)) {
768         RefPtr<Node> implicitTBody = new HTMLTableSectionElement(tbodyTag, m_doc, true /* implicit */);
769         m_currentNode->addChild(implicitTBody.get());
770         setCurrentNode(implicitTBody.get());
771         if (m_view && !implicitTBody->attached())
772             implicitTBody->attach();
773     }
774
775     if (newElement->hasTagName(scriptTag))
776         static_cast<HTMLScriptElement *>(newElement.get())->setCreatedByParser(true);
777
778     if (!m_currentNode->addChild(newElement.get())) {
779         stopParsing();
780         return;
781     }
782     
783     setCurrentNode(newElement.get());
784     if (m_view && !newElement->attached())
785         newElement->attach();
786 }
787
788 void XMLTokenizer::endElementNs()
789 {
790     if (m_parserStopped)
791         return;
792
793     if (m_parserPaused) {
794         m_pendingCallbacks->appendEndElementNSCallback();
795         return;
796     }
797     
798     exitText();
799
800     Node *n = m_currentNode;
801     while (n->implicitNode())
802         n = n->parentNode();
803     RefPtr<Node> parent = n->parentNode();
804     n->closeRenderer();
805     
806     // don't load external scripts for standalone documents (for now)
807     if (n->isElementNode() && m_view && (static_cast<Element*>(n)->hasTagName(scriptTag) 
808 #ifdef SVG_SUPPORT
809                                          || static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag)
810 #endif
811                                          )) {
812
813                                          
814         ASSERT(!m_pendingScript);
815         
816         m_requestingScript = true;
817         
818         Element* scriptElement = static_cast<Element*>(n);        
819         String scriptHref;
820         
821         if (static_cast<Element*>(n)->hasTagName(scriptTag))
822             scriptHref = scriptElement->getAttribute(srcAttr);
823 #ifdef SVG_SUPPORT
824         else if (static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag))
825             scriptHref = scriptElement->getAttribute(XLinkNames::hrefAttr);
826 #endif
827         
828         if (!scriptHref.isEmpty()) {
829             // we have a src attribute 
830             DeprecatedString charset = scriptElement->getAttribute(charsetAttr).deprecatedString();
831             
832             if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) {
833                 m_scriptElement = scriptElement;
834                 m_pendingScript->ref(this);
835                     
836                 // m_pendingScript will be 0 if script was already loaded and ref() executed it
837                 if (m_pendingScript)
838                     pauseParsing();
839             } else 
840                 m_scriptElement = 0;
841
842         } else {
843             DeprecatedString scriptCode = "";
844             for (Node *child = scriptElement->firstChild(); child; child = child->nextSibling()) {
845                 if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE)
846                     scriptCode += static_cast<CharacterData*>(child)->data().deprecatedString();
847             }
848                 
849             m_view->frame()->executeScript(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(toQString(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::sprintf("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
906                 break;
907             case fatal:
908             case nonFatal:
909                 m_errorMessages += String::sprintf("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         toQString(target), toQString(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 KHTML_XSLT
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, toQString(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, toQString(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, toQString(name), toQString(externalID), toQString(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     unsigned short c = decodeNamedEntity(reinterpret_cast<const char*>(name));
1137     if (!c)
1138         return 0;
1139
1140     DeprecatedCString value = DeprecatedString(DeprecatedChar(c)).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     DeprecatedString extId = toQString(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://bugzilla.opendarwin.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 = createQStringParser(&sax, this);
1216 }
1217
1218 void XMLTokenizer::end()
1219 {
1220     if (m_sawXSLTransform) {
1221         m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->URL()));
1222         
1223         m_doc->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
1224         m_doc->updateStyleSelector();
1225         m_doc->setParsing(true);
1226         m_parserStopped = true;
1227     }
1228     
1229     if (m_context) {
1230         // Tell libxml we're done.
1231         xmlParseChunk(m_context, 0, 0, 1);
1232         
1233         if (m_context->myDoc)
1234             xmlFreeDoc(m_context->myDoc);
1235         xmlFreeParserCtxt(m_context);
1236         m_context = 0;
1237     }
1238     
1239     if (m_sawError)
1240         insertErrorMessageBlock();
1241     else {
1242         exitText();
1243         m_doc->updateStyleSelector();
1244     }
1245     
1246     setCurrentNode(0);
1247     m_doc->finishedParsing();    
1248 }
1249
1250 void XMLTokenizer::finish()
1251 {
1252     if (m_parserPaused)
1253         m_finishCalled = true;
1254     else
1255         end();
1256 }
1257
1258 static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages) 
1259 {
1260     ExceptionCode ec = 0;
1261     RefPtr<Element> reportElement = doc->createElementNS(xhtmlNamespaceURI, "parsererror", ec);
1262     reportElement->setAttribute(styleAttr, "white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
1263     
1264     RefPtr<Element> h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1265     reportElement->appendChild(h3.get(), ec);
1266     h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
1267     
1268     RefPtr<Element> fixed = doc->createElementNS(xhtmlNamespaceURI, "div", ec);
1269     reportElement->appendChild(fixed.get(), ec);
1270     fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px");
1271     fixed->appendChild(doc->createTextNode(errorMessages), ec);
1272     
1273     h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1274     reportElement->appendChild(h3.get(), ec);
1275     h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
1276     
1277     return reportElement;
1278 }
1279
1280 void XMLTokenizer::insertErrorMessageBlock()
1281 {
1282     // One or more errors occurred during parsing of the code. Display an error block to the user above
1283     // the normal content (the DOM tree is created manually and includes line/col info regarding 
1284     // where the errors are located)
1285
1286     // Create elements for display
1287     ExceptionCode ec = 0;
1288     Document *doc = m_doc;
1289     Node* documentElement = doc->documentElement();
1290     if (!documentElement) {
1291         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1292         doc->appendChild(rootElement, ec);
1293         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1294         rootElement->appendChild(body, ec);
1295         documentElement = body.get();
1296     }
1297 #ifdef SVG_SUPPORT
1298     else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
1299         // Until our SVG implementation has text support, it is best if we 
1300         // wrap the erroneous SVG document in an xhtml document and render
1301         // the combined document with error messages.
1302         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1303         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1304         rootElement->appendChild(body, ec);
1305         body->appendChild(documentElement, ec);
1306         doc->appendChild(rootElement.get(), ec);
1307         documentElement = body.get();
1308     }
1309 #endif
1310
1311     RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
1312     documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
1313 #ifdef KHTML_XSLT
1314     if (doc->transformSourceDocument()) {
1315         RefPtr<Element> par = doc->createElementNS(xhtmlNamespaceURI, "p", ec);
1316         reportElement->appendChild(par, ec);
1317         par->setAttribute(styleAttr, "white-space: normal");
1318         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);
1319     }
1320 #endif
1321     doc->updateRendering();
1322 }
1323
1324 void XMLTokenizer::notifyFinished(CachedResource *finishedObj)
1325 {
1326     ASSERT(m_pendingScript == finishedObj);
1327     ASSERT(m_pendingScript->accessCount() > 0);
1328         
1329     String cachedScriptUrl = m_pendingScript->url();
1330     String scriptSource = m_pendingScript->script();
1331     bool errorOccurred = m_pendingScript->errorOccurred();
1332     m_pendingScript->deref(this);
1333     m_pendingScript = 0;
1334     
1335     RefPtr<Element> e = m_scriptElement;
1336     m_scriptElement = 0;
1337     
1338     if (errorOccurred) 
1339         EventTargetNodeCast(e.get())->dispatchHTMLEvent(errorEvent, true, false);
1340     else {
1341         m_view->frame()->executeScript(cachedScriptUrl, 0, 0, scriptSource.deprecatedString());
1342         EventTargetNodeCast(e.get())->dispatchHTMLEvent(loadEvent, false, false);
1343     }
1344     
1345     m_scriptElement = 0;
1346     
1347     if (!m_requestingScript)
1348         resumeParsing();
1349 }
1350
1351 bool XMLTokenizer::isWaitingForScripts() const
1352 {
1353     return m_pendingScript != 0;
1354 }
1355
1356 #ifdef KHTML_XSLT
1357 void *xmlDocPtrForString(DocLoader* docLoader, const DeprecatedString &source, const DeprecatedString &url)
1358 {
1359     if (source.isEmpty())
1360             return 0;
1361     // Parse in a single chunk into an xmlDocPtr
1362     // FIXME: Hook up error handlers so that a failure to parse the main document results in
1363     // good error messages.
1364     const DeprecatedChar BOM(0xFEFF);
1365     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
1366
1367     xmlGenericErrorFunc oldErrorFunc = xmlGenericError;
1368     void* oldErrorContext = xmlGenericErrorContext;
1369     
1370     setLoaderForLibXMLCallbacks(docLoader);        
1371     xmlSetGenericErrorFunc(0, errorFunc);
1372     
1373     xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char *>(source.unicode()),
1374                                         source.length() * sizeof(DeprecatedChar),
1375                                         url.ascii(),
1376                                         BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", 
1377                                         XSLT_PARSE_OPTIONS);
1378     
1379     setLoaderForLibXMLCallbacks(0);
1380     xmlSetGenericErrorFunc(oldErrorContext, oldErrorFunc);
1381     
1382     return sourceDoc;
1383 }
1384 #endif
1385
1386 Tokenizer *newXMLTokenizer(Document *d, FrameView *v)
1387 {
1388     return new XMLTokenizer(d, v);
1389 }
1390
1391 int XMLTokenizer::lineNumber() const
1392 {
1393     return m_context->input->line;
1394 }
1395
1396 int XMLTokenizer::columnNumber() const
1397 {
1398     return m_context->input->col;
1399 }
1400
1401 void XMLTokenizer::stopParsing()
1402 {
1403     Tokenizer::stopParsing();
1404     xmlStopParser(m_context);
1405 }
1406
1407 void XMLTokenizer::pauseParsing()
1408 {
1409     if (m_parsingFragment)
1410         return;
1411     
1412     m_parserPaused = true;
1413 }
1414
1415 void XMLTokenizer::resumeParsing()
1416 {
1417     ASSERT(m_parserPaused);
1418     
1419     m_parserPaused = false;
1420     
1421     // First, execute any pending callbacks
1422     while (!m_pendingCallbacks->isEmpty()) {
1423         m_pendingCallbacks->callAndRemoveFirstCallback(this);
1424         
1425         // A callback paused the parser
1426         if (m_parserPaused)
1427             return;
1428     }
1429     
1430     // Then, write any pending data
1431     SegmentedString rest = m_pendingSrc;
1432     m_pendingSrc.clear();
1433     write(rest, false);
1434
1435     // Finally, if finish() has been called and write() didn't result
1436     // in any further callbacks being queued, call end()
1437     if (m_finishCalled && m_pendingCallbacks->isEmpty())
1438         end();
1439 }
1440
1441 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)
1442 {
1443    static_cast<XMLTokenizer *>(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1444 }
1445
1446 static void balancedEndElementNsHandler(void *closure, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
1447 {
1448     static_cast<XMLTokenizer *>(closure)->endElementNs();
1449 }
1450
1451 static void balancedCharactersHandler(void *closure, const xmlChar *s, int len)
1452 {
1453     static_cast<XMLTokenizer *>(closure)->characters(s, len);
1454 }
1455
1456 static void balancedProcessingInstructionHandler(void *closure, const xmlChar *target, const xmlChar *data)
1457 {
1458     static_cast<XMLTokenizer *>(closure)->processingInstruction(target, data);
1459 }
1460
1461 static void balancedCdataBlockHandler(void *closure, const xmlChar *s, int len)
1462 {
1463     static_cast<XMLTokenizer *>(closure)->cdataBlock(s, len);
1464 }
1465
1466 static void balancedCommentHandler(void *closure, const xmlChar *comment)
1467 {
1468     static_cast<XMLTokenizer *>(closure)->comment(comment);
1469 }
1470
1471 static void balancedWarningHandler(void *closure, const char *message, ...)
1472 {
1473     va_list args;
1474     va_start(args, message);
1475     static_cast<XMLTokenizer *>(closure)->error(XMLTokenizer::warning, message, args);
1476     va_end(args);
1477 }
1478
1479 bool parseXMLDocumentFragment(const String &string, DocumentFragment *fragment, Element *parent)
1480 {
1481     XMLTokenizer tokenizer(fragment, parent);
1482     
1483     xmlSAXHandler sax;
1484     memset(&sax, 0, sizeof(sax));
1485
1486     sax.characters = balancedCharactersHandler;
1487     sax.processingInstruction = balancedProcessingInstructionHandler;
1488     sax.startElementNs = balancedStartElementNsHandler;
1489     sax.endElementNs = balancedEndElementNsHandler;
1490     sax.cdataBlock = balancedCdataBlockHandler;
1491     sax.ignorableWhitespace = balancedCdataBlockHandler;
1492     sax.comment = balancedCommentHandler;
1493     sax.warning = balancedWarningHandler;
1494     sax.initialized = XML_SAX2_MAGIC;
1495     
1496     int result = xmlParseBalancedChunkMemory(0, &sax, &tokenizer, 0, 
1497                                             (const xmlChar*)(const char*)(string.deprecatedString().utf8()), 0);
1498     return result == 0;
1499 }
1500
1501 // --------------------------------
1502
1503 struct AttributeParseState {
1504     HashMap<String, String> attributes;
1505     bool gotAttributes;
1506 };
1507
1508
1509 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)
1510 {
1511     if (strcmp(reinterpret_cast<const char *>(xmlLocalName), "attrs") != 0)
1512         return;
1513     
1514     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1515     AttributeParseState *state = static_cast<AttributeParseState *>(ctxt->_private);
1516     
1517     state->gotAttributes = true;
1518     
1519     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
1520     for(int i = 0; i < nb_attributes; i++) {
1521         DeprecatedString attrLocalName = toQString(attributes[i].localname);
1522         int valueLength = (int) (attributes[i].end - attributes[i].value);
1523         String attrValue = toString(attributes[i].value, valueLength);
1524         String attrPrefix = toString(attributes[i].prefix);
1525         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
1526         
1527         state->attributes.set(attrQName, attrValue);
1528     }
1529 }
1530
1531 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
1532 {
1533     AttributeParseState state;
1534     state.gotAttributes = false;
1535
1536     xmlSAXHandler sax;
1537     memset(&sax, 0, sizeof(sax));
1538     sax.startElementNs = attributesStartElementNsHandler;
1539     sax.initialized = XML_SAX2_MAGIC;
1540     xmlParserCtxtPtr parser = createQStringParser(&sax, &state);
1541     DeprecatedString parseString = "<?xml version=\"1.0\"?><attrs " + string.deprecatedString() + " />";
1542     xmlParseChunk(parser, reinterpret_cast<const char *>(parseString.unicode()), parseString.length() * sizeof(DeprecatedChar), 1);
1543     if (parser->myDoc)
1544         xmlFreeDoc(parser->myDoc);
1545     xmlFreeParserCtxt(parser);
1546
1547     attrsOK = state.gotAttributes;
1548     return state.attributes;
1549 }
1550
1551 }