2006-07-27 Eric Seidel <eric@eseidel.com>
[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 "TransferJob.h"
44 #include <libxml/parser.h>
45 #include <libxml/parserInternals.h>
46 #include <wtf/Vector.h>
47
48 #ifdef KHTML_XSLT
49 #include <libxslt/xslt.h>
50 #endif
51
52 #if SVG_SUPPORT
53 #include "SVGNames.h"
54 #include "XLinkNames.h"
55 #endif
56
57 using namespace std;
58
59 namespace WebCore {
60
61 using namespace EventNames;
62 using namespace HTMLNames;
63
64 const int maxErrors = 25;
65
66 typedef HashMap<StringImpl *, StringImpl *> PrefixForNamespaceMap;
67
68 class PendingCallbacks;
69
70 class XMLTokenizer : public Tokenizer, public CachedResourceClient
71 {
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     TransferJob* job = new TransferJob(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     for (Element *element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
582         if (NamedAttrMap *attrs = element->attributes()) {
583             for (unsigned i = 0; i < attrs->length(); i++) {
584                 Attribute *attr = attrs->attributeItem(i);
585                 if (attr->localName() == "xmlns")
586                     m_defaultNamespaceURI = attr->value();
587                 else if (attr->prefix() == "xmlns")
588                     m_prefixToNamespaceMap.set(attr->localName().impl(), attr->value().impl());
589             }
590         }
591     }
592 }
593
594 XMLTokenizer::~XMLTokenizer()
595 {
596     setCurrentNode(0);
597     if (m_parsingFragment && m_doc)
598         m_doc->deref();
599     delete m_pendingCallbacks;
600     if (m_pendingScript)
601         m_pendingScript->deref(this);
602 }
603
604 void XMLTokenizer::setCurrentNode(Node* n)
605 {
606     bool nodeNeedsReference = n && n != m_doc;
607     if (nodeNeedsReference)
608         n->ref(); 
609     if (m_currentNodeIsReferenced) 
610         m_currentNode->deref(); 
611     m_currentNode = n;
612     m_currentNodeIsReferenced = nodeNeedsReference;
613 }
614
615 bool XMLTokenizer::write(const SegmentedString &s, bool /*appendData*/ )
616 {
617     DeprecatedString parseString = s.toString();
618     
619     if (m_sawXSLTransform || !m_sawFirstElement)
620         m_originalSourceForTransform += parseString;
621
622     if (m_parserStopped || m_sawXSLTransform)
623         return false;
624     
625     if (m_parserPaused) {
626         m_pendingSrc.append(s);
627         return false;
628     }
629     
630     if (!m_context)
631         initializeParserContext();
632     
633     // libXML throws an error if you try to switch the encoding for an empty string.
634     if (parseString.length()) {
635         // Hack around libxml2's lack of encoding overide support by manually
636         // resetting the encoding to UTF-16 before every chunk.  Otherwise libxml
637         // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks 
638         // and switch encodings, causing the parse to fail.
639         const DeprecatedChar BOM(0xFEFF);
640         const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
641         xmlSwitchEncoding(m_context, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
642         
643         xmlParseChunk(m_context, reinterpret_cast<const char *>(parseString.unicode()), sizeof(DeprecatedChar) * parseString.length(), 0);
644     }
645     
646     return false;
647 }
648
649 inline DeprecatedString toQString(const xmlChar *str, unsigned int len)
650 {
651     return DeprecatedString::fromUtf8(reinterpret_cast<const char *>(str), len);
652 }
653
654 inline DeprecatedString toQString(const xmlChar *str)
655 {
656     return DeprecatedString::fromUtf8(str ? reinterpret_cast<const char *>(str) : "");
657 }
658
659 inline String toString(const xmlChar* str, unsigned int len)
660 {
661     return DeprecatedString::fromUtf8(reinterpret_cast<const char *>(str), len);
662 }
663
664 inline String toString(const xmlChar* str)
665 {
666     return DeprecatedString::fromUtf8(str ? reinterpret_cast<const char *>(str) : "");
667 }
668
669 struct _xmlSAX2Namespace {
670     const xmlChar *prefix;
671     const xmlChar *uri;
672 };
673 typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
674
675 static inline void handleElementNamespaces(Element *newElement, const xmlChar **libxmlNamespaces, int nb_namespaces, ExceptionCode& ec)
676 {
677     xmlSAX2Namespace *namespaces = reinterpret_cast<xmlSAX2Namespace *>(libxmlNamespaces);
678     for(int i = 0; i < nb_namespaces; i++) {
679         String namespaceQName = "xmlns";
680         String namespaceURI = toString(namespaces[i].uri);
681         if (namespaces[i].prefix)
682             namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
683         newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
684         if (ec) // exception setting attributes
685             return;
686     }
687 }
688
689 struct _xmlSAX2Attributes {
690     const xmlChar *localname;
691     const xmlChar *prefix;
692     const xmlChar *uri;
693     const xmlChar *value;
694     const xmlChar *end;
695 };
696 typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
697
698 static inline void handleElementAttributes(Element *newElement, const xmlChar **libxmlAttributes, int nb_attributes, ExceptionCode& ec)
699 {
700     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
701     for(int i = 0; i < nb_attributes; i++) {
702         String attrLocalName = toQString(attributes[i].localname);
703         int valueLength = (int) (attributes[i].end - attributes[i].value);
704         String attrValue = toQString(attributes[i].value, valueLength);
705         String attrPrefix = toQString(attributes[i].prefix);
706         String attrURI = attrPrefix.isEmpty() ? String() : toQString(attributes[i].uri);
707         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
708         
709         newElement->setAttributeNS(attrURI, attrQName, attrValue, ec);
710         if (ec) // exception setting attributes
711             return;
712     }
713 }
714
715 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)
716 {
717     if (m_parserStopped)
718         return;
719     
720     if (m_parserPaused) {        
721         m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces, nb_attributes, nb_defaulted, libxmlAttributes);
722         return;
723     }
724     
725     m_sawFirstElement = true;
726
727     exitText();
728
729     String localName = toQString(xmlLocalName);
730     String uri = toQString(xmlURI);
731     String prefix = toQString(xmlPrefix);
732     String qName = prefix.isEmpty() ? localName : prefix + ":" + localName;
733     
734     if (m_parsingFragment && uri.isEmpty()) {
735         if (!prefix.isEmpty())
736             uri = String(m_prefixToNamespaceMap.get(prefix.impl()));
737         else
738             uri = m_defaultNamespaceURI;
739     }
740
741     ExceptionCode ec = 0;
742     RefPtr<Element> newElement = m_doc->createElementNS(uri, qName, ec);
743     if (!newElement) {
744         stopParsing();
745         return;
746     }
747     
748     handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec);
749     if (ec) {
750         stopParsing();
751         return;
752     }
753     
754     handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec);
755     if (ec) {
756         stopParsing();
757         return;
758     }
759
760     // FIXME: This hack ensures implicit table bodies get constructed in XHTML and XML files.
761     // We want to consolidate this with the HTML parser and HTML DOM code at some point.
762     // For now, it's too risky to rip that code up.
763     if (m_currentNode->hasTagName(tableTag) && newElement->hasTagName(trTag)) {
764         RefPtr<Node> implicitTBody = new HTMLTableSectionElement(tbodyTag, m_doc, true /* implicit */);
765         m_currentNode->addChild(implicitTBody.get());
766         setCurrentNode(implicitTBody.get());
767         if (m_view && !implicitTBody->attached())
768             implicitTBody->attach();
769     }
770
771     if (newElement->hasTagName(scriptTag))
772         static_cast<HTMLScriptElement *>(newElement.get())->setCreatedByParser(true);
773
774     if (!m_currentNode->addChild(newElement.get())) {
775         stopParsing();
776         return;
777     }
778     
779     setCurrentNode(newElement.get());
780     if (m_view && !newElement->attached())
781         newElement->attach();
782 }
783
784 void XMLTokenizer::endElementNs()
785 {
786     if (m_parserStopped)
787         return;
788
789     if (m_parserPaused) {
790         m_pendingCallbacks->appendEndElementNSCallback();
791         return;
792     }
793     
794     exitText();
795
796     Node *n = m_currentNode;
797     while (n->implicitNode())
798         n = n->parentNode();
799     RefPtr<Node> parent = n->parentNode();
800     n->closeRenderer();
801     
802     // don't load external scripts for standalone documents (for now)
803     if (n->isElementNode() && m_view && (static_cast<Element*>(n)->hasTagName(scriptTag) 
804 #if SVG_SUPPORT
805                                          || static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag)
806 #endif
807                                          )) {
808
809                                          
810         ASSERT(!m_pendingScript);
811         
812         m_requestingScript = true;
813         
814         Element* scriptElement = static_cast<Element*>(n);        
815         String scriptHref;
816         
817         if (static_cast<Element*>(n)->hasTagName(scriptTag))
818             scriptHref = scriptElement->getAttribute(srcAttr);
819 #if SVG_SUPPORT
820         else if (static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag))
821             scriptHref = scriptElement->getAttribute(XLinkNames::hrefAttr);
822 #endif
823         
824         if (!scriptHref.isEmpty()) {
825             // we have a src attribute 
826             DeprecatedString charset = scriptElement->getAttribute(charsetAttr).deprecatedString();
827             
828             if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) {
829                 m_scriptElement = scriptElement;
830                 m_pendingScript->ref(this);
831                     
832                 // m_pendingScript will be 0 if script was already loaded and ref() executed it
833                 if (m_pendingScript)
834                     pauseParsing();
835             } else 
836                 m_scriptElement = 0;
837
838         } else {
839             DeprecatedString scriptCode = "";
840             for (Node *child = scriptElement->firstChild(); child; child = child->nextSibling()) {
841                 if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE)
842                     scriptCode += static_cast<CharacterData*>(child)->data().deprecatedString();
843             }
844                 
845             m_view->frame()->executeScript(0, scriptCode);
846         }
847         
848         m_requestingScript = false;
849     }
850
851     setCurrentNode(parent.get());
852 }
853
854 void XMLTokenizer::characters(const xmlChar *s, int len)
855 {
856     if (m_parserStopped)
857         return;
858     
859     if (m_parserPaused) {
860         m_pendingCallbacks->appendCharactersCallback(s, len);
861         return;
862     }
863     
864     if (m_currentNode->isTextNode() || enterText()) {
865         ExceptionCode ec = 0;
866         static_cast<Text*>(m_currentNode)->appendData(toQString(s, len), ec);
867     }
868 }
869
870 bool XMLTokenizer::enterText()
871 {
872     RefPtr<Node> newNode = new Text(m_doc, "");
873     if (!m_currentNode->addChild(newNode.get()))
874         return false;
875     setCurrentNode(newNode.get());
876     return true;
877 }
878
879 void XMLTokenizer::exitText()
880 {
881     if (m_parserStopped)
882         return;
883
884     if (!m_currentNode || !m_currentNode->isTextNode())
885         return;
886
887     if (m_view && m_currentNode && !m_currentNode->attached())
888         m_currentNode->attach();
889
890     // FIXME: What's the right thing to do if the parent is really 0?
891     // Just leaving the current node set to the text node doesn't make much sense.
892     if (Node* par = m_currentNode->parentNode())
893         setCurrentNode(par);
894 }
895
896 void XMLTokenizer::handleError(ErrorType type, const char* m, int lineNumber, int columnNumber)
897 {
898     if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber && m_lastErrorColumn != columnNumber)) {
899         switch (type) {
900             case warning:
901                 m_errorMessages += String::sprintf("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
902                 break;
903             case fatal:
904             case nonFatal:
905                 m_errorMessages += String::sprintf("error on line %d at column %d: %s", lineNumber, columnNumber, m);
906         }
907         
908         m_lastErrorLine = lineNumber;
909         m_lastErrorColumn = columnNumber;
910         ++m_errorCount;
911     }
912     
913     if (type != warning)
914         m_sawError = true;
915     
916     if (type == fatal)
917         stopParsing();    
918 }
919
920 void XMLTokenizer::error(ErrorType type, const char *message, va_list args)
921 {
922     if (m_parserStopped)
923         return;
924
925 #if WIN32
926     char m[1024];
927     vsnprintf(m, sizeof(m) - 1, message, args);
928 #else
929     char *m;
930     vasprintf(&m, message, args);
931 #endif
932     
933     if (m_parserPaused)
934         m_pendingCallbacks->appendErrorCallback(type, m, lineNumber(), columnNumber());
935     else
936         handleError(type, m, lineNumber(), columnNumber());
937
938 #if !WIN32
939     free(m);
940 #endif
941 }
942
943 void XMLTokenizer::processingInstruction(const xmlChar *target, const xmlChar *data)
944 {
945     if (m_parserStopped)
946         return;
947
948     if (m_parserPaused) {
949         m_pendingCallbacks->appendProcessingInstructionCallback(target, data);
950         return;
951     }
952     
953     exitText();
954
955     // ### handle exceptions
956     int exception = 0;
957     RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction(
958         toQString(target), toQString(data), exception);
959     if (exception)
960         return;
961
962     if (!m_currentNode->addChild(pi.get()))
963         return;
964     if (m_view && !pi->attached())
965         pi->attach();
966
967     // don't load stylesheets for standalone documents
968     if (m_doc->frame()) {
969         m_sawXSLTransform = !m_sawFirstElement && !pi->checkStyleSheet();
970 #ifdef KHTML_XSLT
971         // Pretend we didn't see this PI if we're the result of a transform.
972         if (m_sawXSLTransform && !m_doc->transformSourceDocument())
973 #else
974         if (m_sawXSLTransform)
975 #endif
976             // Stop the SAX parser.
977             stopParsing();
978     }
979 }
980
981 void XMLTokenizer::cdataBlock(const xmlChar *s, int len)
982 {
983     if (m_parserStopped)
984         return;
985
986     if (m_parserPaused) {
987         m_pendingCallbacks->appendCDATABlockCallback(s, len);
988         return;
989     }
990     
991     exitText();
992
993     RefPtr<Node> newNode = new CDATASection(m_doc, toQString(s, len));
994     if (!m_currentNode->addChild(newNode.get()))
995         return;
996     if (m_view && !newNode->attached())
997         newNode->attach();
998 }
999
1000 void XMLTokenizer::comment(const xmlChar *s)
1001 {
1002     if (m_parserStopped)
1003         return;
1004
1005     if (m_parserPaused) {
1006         m_pendingCallbacks->appendCommentCallback(s);
1007         return;
1008     }
1009     
1010     exitText();
1011
1012     RefPtr<Node> newNode = new Comment(m_doc, toQString(s));
1013     m_currentNode->addChild(newNode.get());
1014     if (m_view && !newNode->attached())
1015         newNode->attach();
1016 }
1017
1018 void XMLTokenizer::internalSubset(const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
1019 {
1020     if (m_parserStopped)
1021         return;
1022
1023     if (m_parserPaused) {
1024         m_pendingCallbacks->appendInternalSubsetCallback(name, externalID, systemID);
1025         return;
1026     }
1027     
1028     Document *doc = m_doc;
1029     if (!doc)
1030         return;
1031
1032     doc->setDocType(new DocumentType(doc, toQString(name), toQString(externalID), toQString(systemID)));
1033 }
1034
1035 inline XMLTokenizer *getTokenizer(void *closure)
1036 {
1037     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1038     return static_cast<XMLTokenizer *>(ctxt->_private);
1039 }
1040
1041 // This is a hack around http://bugzilla.gnome.org/show_bug.cgi?id=159219
1042 // Otherwise libxml seems to call all the SAX callbacks twice for any replaced entity.
1043 static inline bool hackAroundLibXMLEntityBug(void *closure)
1044 {
1045     return static_cast<xmlParserCtxtPtr>(closure)->node;
1046 }
1047
1048 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)
1049 {
1050     if (hackAroundLibXMLEntityBug(closure))
1051         return;
1052
1053     getTokenizer(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1054 }
1055
1056 static void endElementNsHandler(void *closure, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
1057 {
1058     if (hackAroundLibXMLEntityBug(closure))
1059         return;
1060     
1061     getTokenizer(closure)->endElementNs();
1062 }
1063
1064 static void charactersHandler(void *closure, const xmlChar *s, int len)
1065 {
1066     if (hackAroundLibXMLEntityBug(closure))
1067         return;
1068     
1069     getTokenizer(closure)->characters(s, len);
1070 }
1071
1072 static void processingInstructionHandler(void *closure, const xmlChar *target, const xmlChar *data)
1073 {
1074     if (hackAroundLibXMLEntityBug(closure))
1075         return;
1076     
1077     getTokenizer(closure)->processingInstruction(target, data);
1078 }
1079
1080 static void cdataBlockHandler(void *closure, const xmlChar *s, int len)
1081 {
1082     if (hackAroundLibXMLEntityBug(closure))
1083         return;
1084     
1085     getTokenizer(closure)->cdataBlock(s, len);
1086 }
1087
1088 static void commentHandler(void *closure, const xmlChar *comment)
1089 {
1090     if (hackAroundLibXMLEntityBug(closure))
1091         return;
1092     
1093     getTokenizer(closure)->comment(comment);
1094 }
1095
1096 static void warningHandler(void *closure, const char *message, ...)
1097 {
1098     va_list args;
1099     va_start(args, message);
1100     getTokenizer(closure)->error(XMLTokenizer::warning, message, args);
1101     va_end(args);
1102 }
1103
1104 static void fatalErrorHandler(void *closure, const char *message, ...)
1105 {
1106     va_list args;
1107     va_start(args, message);
1108     getTokenizer(closure)->error(XMLTokenizer::fatal, message, args);
1109     va_end(args);
1110 }
1111
1112 static void normalErrorHandler(void *closure, const char *message, ...)
1113 {
1114     va_list args;
1115     va_start(args, message);
1116     getTokenizer(closure)->error(XMLTokenizer::nonFatal, message, args);
1117     va_end(args);
1118 }
1119
1120 // Using a global variable entity and marking it XML_INTERNAL_PREDEFINED_ENTITY is
1121 // a hack to avoid malloc/free. Using a global variable like this could cause trouble
1122 // if libxml implementation details were to change
1123 static xmlChar sharedXHTMLEntityResult[5] = {0,0,0,0,0};
1124 static xmlEntity sharedXHTMLEntity = {
1125     0, XML_ENTITY_DECL, 0, 0, 0, 0, 0, 0, 0, 
1126     sharedXHTMLEntityResult, sharedXHTMLEntityResult, 0,
1127     XML_INTERNAL_PREDEFINED_ENTITY, 0, 0, 0, 0, 0
1128 };
1129
1130 static xmlEntityPtr getXHTMLEntity(const xmlChar* name)
1131 {
1132     unsigned short c = decodeNamedEntity(reinterpret_cast<const char*>(name));
1133     if (!c)
1134         return 0;
1135
1136     DeprecatedCString value = DeprecatedString(DeprecatedChar(c)).utf8();
1137     assert(value.length() < 5);
1138     sharedXHTMLEntity.length = value.length();
1139     sharedXHTMLEntity.name = name;
1140     memcpy(sharedXHTMLEntityResult, value.data(), sharedXHTMLEntity.length + 1);
1141
1142     return &sharedXHTMLEntity;
1143 }
1144
1145 static xmlEntityPtr getEntityHandler(void *closure, const xmlChar *name)
1146 {
1147     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1148     xmlEntityPtr ent = xmlGetPredefinedEntity(name);
1149     if (ent)
1150         return ent;
1151
1152     ent = xmlGetDocEntity(ctxt->myDoc, name);
1153     if (!ent && getTokenizer(closure)->isXHTMLDocument())
1154         ent = getXHTMLEntity(name);
1155     
1156     return ent;
1157 }
1158
1159 static void internalSubsetHandler(void *closure, const xmlChar *name, const xmlChar *externalID, const xmlChar *systemID)
1160 {
1161     getTokenizer(closure)->internalSubset(name, externalID, systemID);
1162     xmlSAX2InternalSubset(closure, name, externalID, systemID);
1163 }
1164
1165 static void externalSubsetHandler(void *closure, const xmlChar *name, const xmlChar *externalId, const xmlChar *systemId)
1166 {
1167     DeprecatedString extId = toQString(externalId);
1168     if ((extId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
1169         || (extId == "-//W3C//DTD XHTML 1.1//EN")
1170         || (extId == "-//W3C//DTD XHTML 1.0 Strict//EN")
1171         || (extId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
1172         || (extId == "-//W3C//DTD XHTML Basic 1.0//EN")
1173         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
1174         || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
1175         || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
1176         getTokenizer(closure)->setIsXHTMLDocument(true); // controls if we replace entities or not.
1177 }
1178
1179 static void ignorableWhitespaceHandler(void *ctx, const xmlChar *ch, int len)
1180 {
1181     // nothing to do, but we need this to work around a crasher
1182     // http://bugzilla.gnome.org/show_bug.cgi?id=172255
1183     // http://bugzilla.opendarwin.org/show_bug.cgi?id=5792
1184 }
1185
1186 void XMLTokenizer::initializeParserContext()
1187 {
1188     xmlSAXHandler sax;
1189     memset(&sax, 0, sizeof(sax));
1190     sax.error = normalErrorHandler;
1191     sax.fatalError = fatalErrorHandler;
1192     sax.characters = charactersHandler;
1193     sax.processingInstruction = processingInstructionHandler;
1194     sax.cdataBlock = cdataBlockHandler;
1195     sax.comment = commentHandler;
1196     sax.warning = warningHandler;
1197     sax.startElementNs = startElementNsHandler;
1198     sax.endElementNs = endElementNsHandler;
1199     sax.getEntity = getEntityHandler;
1200     sax.startDocument = xmlSAX2StartDocument;
1201     sax.internalSubset = internalSubsetHandler;
1202     sax.externalSubset = externalSubsetHandler;
1203     sax.ignorableWhitespace = ignorableWhitespaceHandler;
1204     sax.entityDecl = xmlSAX2EntityDecl;
1205     sax.initialized = XML_SAX2_MAGIC;
1206     
1207     m_parserStopped = false;
1208     m_sawError = false;
1209     m_sawXSLTransform = false;
1210     m_sawFirstElement = false;
1211     m_context = createQStringParser(&sax, this);
1212 }
1213
1214 void XMLTokenizer::end()
1215 {
1216     if (m_sawXSLTransform) {
1217         m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->URL()));
1218         
1219         m_doc->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
1220         m_doc->updateStyleSelector();
1221         m_doc->setParsing(true);
1222         m_parserStopped = true;
1223     }
1224     
1225     if (m_context) {
1226         // Tell libxml we're done.
1227         xmlParseChunk(m_context, 0, 0, 1);
1228         
1229         if (m_context->myDoc)
1230             xmlFreeDoc(m_context->myDoc);
1231         xmlFreeParserCtxt(m_context);
1232         m_context = 0;
1233     }
1234     
1235     if (m_sawError)
1236         insertErrorMessageBlock();
1237     else {
1238         exitText();
1239         m_doc->updateStyleSelector();
1240     }
1241     
1242     setCurrentNode(0);
1243     m_doc->finishedParsing();    
1244 }
1245
1246 void XMLTokenizer::finish()
1247 {
1248     if (m_parserPaused)
1249         m_finishCalled = true;
1250     else
1251         end();
1252 }
1253
1254 static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages) 
1255 {
1256     ExceptionCode ec = 0;
1257     RefPtr<Element> reportElement = doc->createElementNS(xhtmlNamespaceURI, "parsererror", ec);
1258     reportElement->setAttribute(styleAttr, "white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
1259     
1260     RefPtr<Element> h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1261     reportElement->appendChild(h3.get(), ec);
1262     h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
1263     
1264     RefPtr<Element> fixed = doc->createElementNS(xhtmlNamespaceURI, "div", ec);
1265     reportElement->appendChild(fixed.get(), ec);
1266     fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px");
1267     fixed->appendChild(doc->createTextNode(errorMessages), ec);
1268     
1269     h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
1270     reportElement->appendChild(h3.get(), ec);
1271     h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
1272     
1273     return reportElement;
1274 }
1275
1276 void XMLTokenizer::insertErrorMessageBlock()
1277 {
1278     // One or more errors occurred during parsing of the code. Display an error block to the user above
1279     // the normal content (the DOM tree is created manually and includes line/col info regarding 
1280     // where the errors are located)
1281
1282     // Create elements for display
1283     ExceptionCode ec = 0;
1284     Document *doc = m_doc;
1285     Node* documentElement = doc->documentElement();
1286     if (!documentElement) {
1287         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1288         doc->appendChild(rootElement, ec);
1289         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1290         rootElement->appendChild(body, ec);
1291         documentElement = body.get();
1292     }
1293 #if SVG_SUPPORT
1294     else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
1295         // Until our SVG implementation has text support, it is best if we 
1296         // wrap the erroneous SVG document in an xhtml document and render
1297         // the combined document with error messages.
1298         RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
1299         RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
1300         rootElement->appendChild(body, ec);
1301         body->appendChild(documentElement, ec);
1302         doc->appendChild(rootElement.get(), ec);
1303         documentElement = body.get();
1304     }
1305 #endif
1306
1307     RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
1308     documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
1309 #ifdef KHTML_XSLT
1310     if (doc->transformSourceDocument()) {
1311         RefPtr<Element> par = doc->createElementNS(xhtmlNamespaceURI, "p", ec);
1312         reportElement->appendChild(par, ec);
1313         par->setAttribute(styleAttr, "white-space: normal");
1314         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);
1315     }
1316 #endif
1317     doc->updateRendering();
1318 }
1319
1320 void XMLTokenizer::notifyFinished(CachedResource *finishedObj)
1321 {
1322     ASSERT(m_pendingScript == finishedObj);
1323     ASSERT(m_pendingScript->accessCount() > 0);
1324         
1325     String cachedScriptUrl = m_pendingScript->url();
1326     String scriptSource = m_pendingScript->script();
1327     bool errorOccurred = m_pendingScript->errorOccurred();
1328     m_pendingScript->deref(this);
1329     m_pendingScript = 0;
1330     
1331     RefPtr<Element> e = m_scriptElement;
1332     m_scriptElement = 0;
1333     
1334     if (errorOccurred) 
1335         EventTargetNodeCast(e.get())->dispatchHTMLEvent(errorEvent, true, false);
1336     else {
1337         m_view->frame()->executeScript(cachedScriptUrl, 0, 0, scriptSource.deprecatedString());
1338         EventTargetNodeCast(e.get())->dispatchHTMLEvent(loadEvent, false, false);
1339     }
1340     
1341     m_scriptElement = 0;
1342     
1343     if (!m_requestingScript)
1344         resumeParsing();
1345 }
1346
1347 bool XMLTokenizer::isWaitingForScripts() const
1348 {
1349     return m_pendingScript != 0;
1350 }
1351
1352 #ifdef KHTML_XSLT
1353 void *xmlDocPtrForString(DocLoader* docLoader, const DeprecatedString &source, const DeprecatedString &url)
1354 {
1355     if (source.isEmpty())
1356             return 0;
1357     // Parse in a single chunk into an xmlDocPtr
1358     // FIXME: Hook up error handlers so that a failure to parse the main document results in
1359     // good error messages.
1360     const DeprecatedChar BOM(0xFEFF);
1361     const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char *>(&BOM);
1362
1363     xmlGenericErrorFunc oldErrorFunc = xmlGenericError;
1364     void* oldErrorContext = xmlGenericErrorContext;
1365     
1366     setLoaderForLibXMLCallbacks(docLoader);        
1367     xmlSetGenericErrorFunc(0, errorFunc);
1368     
1369     xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char *>(source.unicode()),
1370                                         source.length() * sizeof(DeprecatedChar),
1371                                         url.ascii(),
1372                                         BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", 
1373                                         XSLT_PARSE_OPTIONS);
1374     
1375     setLoaderForLibXMLCallbacks(0);
1376     xmlSetGenericErrorFunc(oldErrorContext, oldErrorFunc);
1377     
1378     return sourceDoc;
1379 }
1380 #endif
1381
1382 Tokenizer *newXMLTokenizer(Document *d, FrameView *v)
1383 {
1384     return new XMLTokenizer(d, v);
1385 }
1386
1387 int XMLTokenizer::lineNumber() const
1388 {
1389     return m_context->input->line;
1390 }
1391
1392 int XMLTokenizer::columnNumber() const
1393 {
1394     return m_context->input->col;
1395 }
1396
1397 void XMLTokenizer::stopParsing()
1398 {
1399     Tokenizer::stopParsing();
1400     xmlStopParser(m_context);
1401 }
1402
1403 void XMLTokenizer::pauseParsing()
1404 {
1405     if (m_parsingFragment)
1406         return;
1407     
1408     m_parserPaused = true;
1409 }
1410
1411 void XMLTokenizer::resumeParsing()
1412 {
1413     ASSERT(m_parserPaused);
1414     
1415     m_parserPaused = false;
1416     
1417     // First, execute any pending callbacks
1418     while (!m_pendingCallbacks->isEmpty()) {
1419         m_pendingCallbacks->callAndRemoveFirstCallback(this);
1420         
1421         // A callback paused the parser
1422         if (m_parserPaused)
1423             return;
1424     }
1425     
1426     // Then, write any pending data
1427     SegmentedString rest = m_pendingSrc;
1428     m_pendingSrc.clear();
1429     write(rest, false);
1430     
1431     // Finally, if finish() has been called, call end()
1432     if (m_finishCalled)
1433         end();
1434 }
1435
1436 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)
1437 {
1438    static_cast<XMLTokenizer *>(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
1439 }
1440
1441 static void balancedEndElementNsHandler(void *closure, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
1442 {
1443     static_cast<XMLTokenizer *>(closure)->endElementNs();
1444 }
1445
1446 static void balancedCharactersHandler(void *closure, const xmlChar *s, int len)
1447 {
1448     static_cast<XMLTokenizer *>(closure)->characters(s, len);
1449 }
1450
1451 static void balancedProcessingInstructionHandler(void *closure, const xmlChar *target, const xmlChar *data)
1452 {
1453     static_cast<XMLTokenizer *>(closure)->processingInstruction(target, data);
1454 }
1455
1456 static void balancedCdataBlockHandler(void *closure, const xmlChar *s, int len)
1457 {
1458     static_cast<XMLTokenizer *>(closure)->cdataBlock(s, len);
1459 }
1460
1461 static void balancedCommentHandler(void *closure, const xmlChar *comment)
1462 {
1463     static_cast<XMLTokenizer *>(closure)->comment(comment);
1464 }
1465
1466 static void balancedWarningHandler(void *closure, const char *message, ...)
1467 {
1468     va_list args;
1469     va_start(args, message);
1470     static_cast<XMLTokenizer *>(closure)->error(XMLTokenizer::warning, message, args);
1471     va_end(args);
1472 }
1473
1474 bool parseXMLDocumentFragment(const String &string, DocumentFragment *fragment, Element *parent)
1475 {
1476     XMLTokenizer tokenizer(fragment, parent);
1477     
1478     xmlSAXHandler sax;
1479     memset(&sax, 0, sizeof(sax));
1480
1481     sax.characters = balancedCharactersHandler;
1482     sax.processingInstruction = balancedProcessingInstructionHandler;
1483     sax.startElementNs = balancedStartElementNsHandler;
1484     sax.endElementNs = balancedEndElementNsHandler;
1485     sax.cdataBlock = balancedCdataBlockHandler;
1486     sax.ignorableWhitespace = balancedCdataBlockHandler;
1487     sax.comment = balancedCommentHandler;
1488     sax.warning = balancedWarningHandler;
1489     sax.initialized = XML_SAX2_MAGIC;
1490     
1491     int result = xmlParseBalancedChunkMemory(0, &sax, &tokenizer, 0, 
1492                                             (const xmlChar*)(const char*)(string.deprecatedString().utf8()), 0);
1493     return result == 0;
1494 }
1495
1496 // --------------------------------
1497
1498 struct AttributeParseState {
1499     HashMap<String, String> attributes;
1500     bool gotAttributes;
1501 };
1502
1503
1504 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)
1505 {
1506     if (strcmp(reinterpret_cast<const char *>(xmlLocalName), "attrs") != 0)
1507         return;
1508     
1509     xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
1510     AttributeParseState *state = static_cast<AttributeParseState *>(ctxt->_private);
1511     
1512     state->gotAttributes = true;
1513     
1514     xmlSAX2Attributes *attributes = reinterpret_cast<xmlSAX2Attributes *>(libxmlAttributes);
1515     for(int i = 0; i < nb_attributes; i++) {
1516         DeprecatedString attrLocalName = toQString(attributes[i].localname);
1517         int valueLength = (int) (attributes[i].end - attributes[i].value);
1518         String attrValue = toString(attributes[i].value, valueLength);
1519         String attrPrefix = toString(attributes[i].prefix);
1520         String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
1521         
1522         state->attributes.set(attrQName, attrValue);
1523     }
1524 }
1525
1526 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
1527 {
1528     AttributeParseState state;
1529     state.gotAttributes = false;
1530
1531     xmlSAXHandler sax;
1532     memset(&sax, 0, sizeof(sax));
1533     sax.startElementNs = attributesStartElementNsHandler;
1534     sax.initialized = XML_SAX2_MAGIC;
1535     xmlParserCtxtPtr parser = createQStringParser(&sax, &state);
1536     DeprecatedString parseString = "<?xml version=\"1.0\"?><attrs " + string.deprecatedString() + " />";
1537     xmlParseChunk(parser, reinterpret_cast<const char *>(parseString.unicode()), parseString.length() * sizeof(DeprecatedChar), 1);
1538     if (parser->myDoc)
1539         xmlFreeDoc(parser->myDoc);
1540     xmlFreeParserCtxt(parser);
1541
1542     attrsOK = state.gotAttributes;
1543     return state.attributes;
1544 }
1545
1546 }