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