mshtml: Implement IHTMLDOMNode replaceChild.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2010-2011 Adam Martinson for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include "config.h"
26
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
37
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
50 #include "dispex.h"
51
52 #include "wine/debug.h"
53 #include "wine/list.h"
54
55 #include "msxml_private.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58
59 #ifdef HAVE_LIBXML2
60
61 /* not defined in older versions */
62 #define XML_SAVE_FORMAT     1
63 #define XML_SAVE_NO_DECL    2
64 #define XML_SAVE_NO_EMPTY   4
65 #define XML_SAVE_NO_XHTML   8
66 #define XML_SAVE_XHTML     16
67 #define XML_SAVE_AS_XML    32
68 #define XML_SAVE_AS_HTML   64
69
70 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
71 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
72 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
73 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
74 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
75 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
76 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77
78 /* Anything that passes the test_get_ownerDocument()
79  * tests can go here (data shared between all instances).
80  * We need to preserve this when reloading a document,
81  * and also need access to it from the libxml backend. */
82 typedef struct _domdoc_properties {
83     MSXML_VERSION version;
84     VARIANT_BOOL preserving;
85     IXMLDOMSchemaCollection2* schemaCache;
86     struct list selectNsList;
87     xmlChar const* selectNsStr;
88     LONG selectNsStr_len;
89     BOOL XPath;
90 } domdoc_properties;
91
92 typedef struct ConnectionPoint ConnectionPoint;
93 typedef struct domdoc domdoc;
94
95 struct ConnectionPoint
96 {
97     IConnectionPoint IConnectionPoint_iface;
98     const IID *iid;
99
100     ConnectionPoint *next;
101     IConnectionPointContainer *container;
102     domdoc *doc;
103
104     union
105     {
106         IUnknown *unk;
107         IDispatch *disp;
108         IPropertyNotifySink *propnotif;
109     } *sinks;
110     DWORD sinks_size;
111 };
112
113 typedef enum {
114     EVENTID_READYSTATECHANGE = 0,
115     EVENTID_DATAAVAILABLE,
116     EVENTID_TRANSFORMNODE,
117     EVENTID_LAST
118 } eventid_t;
119
120 struct domdoc
121 {
122     xmlnode node;
123     IXMLDOMDocument3          IXMLDOMDocument3_iface;
124     IPersistStreamInit        IPersistStreamInit_iface;
125     IObjectWithSite           IObjectWithSite_iface;
126     IObjectSafety             IObjectSafety_iface;
127     ISupportErrorInfo         ISupportErrorInfo_iface;
128     IConnectionPointContainer IConnectionPointContainer_iface;
129     LONG ref;
130     VARIANT_BOOL async;
131     VARIANT_BOOL validating;
132     VARIANT_BOOL resolving;
133     domdoc_properties* properties;
134     bsc_t *bsc;
135     HRESULT error;
136
137     /* IPersistStream */
138     IStream *stream;
139
140     /* IObjectWithSite*/
141     IUnknown *site;
142
143     /* IObjectSafety */
144     DWORD safeopt;
145
146     /* connection list */
147     ConnectionPoint *cp_list;
148     ConnectionPoint cp_domdocevents;
149     ConnectionPoint cp_propnotif;
150     ConnectionPoint cp_dispatch;
151
152     /* events */
153     IDispatch *events[EVENTID_LAST];
154 };
155
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
157 {
158     IDispatch *disp;
159
160     switch (V_VT(v))
161     {
162     case VT_UNKNOWN:
163         if (V_UNKNOWN(v))
164             IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165         else
166             disp = NULL;
167         break;
168     case VT_DISPATCH:
169         disp = V_DISPATCH(v);
170         if (disp) IDispatch_AddRef(disp);
171         break;
172     default:
173         return DISP_E_TYPEMISMATCH;
174     }
175
176     if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177     doc->events[eid] = disp;
178
179     return S_OK;
180 }
181
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
183 {
184     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 }
186
187 /*
188   In native windows, the whole lifetime management of XMLDOMNodes is
189   managed automatically using reference counts. Wine emulates that by
190   maintaining a reference count to the document that is increased for
191   each IXMLDOMNode pointer passed out for this document. If all these
192   pointers are gone, the document is unreachable and gets freed, that
193   is, all nodes in the tree of the document get freed.
194
195   You are able to create nodes that are associated to a document (in
196   fact, in msxml's XMLDOM model, all nodes are associated to a document),
197   but not in the tree of that document, for example using the createFoo
198   functions from IXMLDOMDocument. These nodes do not get cleaned up
199   by libxml, so we have to do it ourselves.
200
201   To catch these nodes, a list of "orphan nodes" is introduced.
202   It contains pointers to all roots of node trees that are
203   associated with the document without being part of the document
204   tree. All nodes with parent==NULL (except for the document root nodes)
205   should be in the orphan node list of their document. All orphan nodes
206   get freed together with the document itself.
207  */
208
209 typedef struct _xmldoc_priv {
210     LONG refs;
211     struct list orphans;
212     domdoc_properties* properties;
213 } xmldoc_priv;
214
215 typedef struct _orphan_entry {
216     struct list entry;
217     xmlNode * node;
218 } orphan_entry;
219
220 typedef struct _select_ns_entry {
221     struct list entry;
222     xmlChar const* prefix;
223     xmlChar prefix_end;
224     xmlChar const* href;
225     xmlChar href_end;
226 } select_ns_entry;
227
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
229 {
230     return doc->_private;
231 }
232
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
234 {
235     return priv_from_xmlDocPtr(doc)->properties;
236 }
237
238 BOOL is_xpathmode(const xmlDocPtr doc)
239 {
240     return properties_from_xmlDocPtr(doc)->XPath;
241 }
242
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
244 {
245     properties_from_xmlDocPtr(doc)->XPath = xpath;
246 }
247
248 int registerNamespaces(xmlXPathContextPtr ctxt)
249 {
250     int n = 0;
251     const select_ns_entry* ns = NULL;
252     const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
253
254     TRACE("(%p)\n", ctxt);
255
256     LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
257     {
258         xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259         ++n;
260     }
261
262     return n;
263 }
264
265 static inline void clear_selectNsList(struct list* pNsList)
266 {
267     select_ns_entry *ns, *ns2;
268     LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
269     {
270         heap_free( ns );
271     }
272     list_init(pNsList);
273 }
274
275 static xmldoc_priv * create_priv(void)
276 {
277     xmldoc_priv *priv;
278     priv = heap_alloc( sizeof (*priv) );
279
280     if (priv)
281     {
282         priv->refs = 0;
283         list_init( &priv->orphans );
284         priv->properties = NULL;
285     }
286
287     return priv;
288 }
289
290 static domdoc_properties * create_properties(MSXML_VERSION version)
291 {
292     domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
293
294     list_init(&properties->selectNsList);
295     properties->preserving = VARIANT_FALSE;
296     properties->schemaCache = NULL;
297     properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298     properties->selectNsStr_len = 0;
299
300     /* properties that are dependent on object versions */
301     properties->version = version;
302     properties->XPath = (version == MSXML4 || version == MSXML6);
303
304     return properties;
305 }
306
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
308 {
309     domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310     select_ns_entry const* ns = NULL;
311     select_ns_entry* new_ns = NULL;
312     int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313     ptrdiff_t offset;
314
315     if (pcopy)
316     {
317         pcopy->version = properties->version;
318         pcopy->preserving = properties->preserving;
319         pcopy->schemaCache = properties->schemaCache;
320         if (pcopy->schemaCache)
321             IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322         pcopy->XPath = properties->XPath;
323         pcopy->selectNsStr_len = properties->selectNsStr_len;
324         list_init( &pcopy->selectNsList );
325         pcopy->selectNsStr = heap_alloc(len);
326         memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327         offset = pcopy->selectNsStr - properties->selectNsStr;
328
329         LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
330         {
331             new_ns = heap_alloc(sizeof(select_ns_entry));
332             memcpy(new_ns, ns, sizeof(select_ns_entry));
333             new_ns->href += offset;
334             new_ns->prefix += offset;
335             list_add_tail(&pcopy->selectNsList, &new_ns->entry);
336         }
337
338     }
339
340     return pcopy;
341 }
342
343 static void free_properties(domdoc_properties* properties)
344 {
345     if (properties)
346     {
347         if (properties->schemaCache)
348             IXMLDOMSchemaCollection2_Release(properties->schemaCache);
349         clear_selectNsList(&properties->selectNsList);
350         heap_free((xmlChar*)properties->selectNsStr);
351         heap_free(properties);
352     }
353 }
354
355 /* links a "<?xml" node as a first child */
356 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
357 {
358     assert(doc != NULL);
359     if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
360 }
361
362 /* unlinks a first "<?xml" child if it was created */
363 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
364 {
365     xmlNodePtr node;
366
367     assert(doc != NULL);
368
369     if (doc->standalone != -1)
370     {
371         node = doc->children;
372         xmlUnlinkNode( node );
373     }
374     else
375         node = NULL;
376
377     return node;
378 }
379
380 BOOL is_preserving_whitespace(xmlNodePtr node)
381 {
382     domdoc_properties* properties = NULL;
383     /* during parsing the xmlDoc._private stuff is not there */
384     if (priv_from_xmlDocPtr(node->doc))
385         properties = properties_from_xmlDocPtr(node->doc);
386     return ((properties && properties->preserving == VARIANT_TRUE) ||
387             xmlNodeGetSpacePreserve(node) == 1);
388 }
389
390 static inline BOOL strn_isspace(xmlChar const* str, int len)
391 {
392     for (; str && len > 0 && *str; ++str, --len)
393         if (!isspace(*str))
394             break;
395
396     return len == 0;
397 }
398
399 static void sax_characters(void *ctx, const xmlChar *ch, int len)
400 {
401     xmlParserCtxtPtr ctxt;
402     const domdoc *This;
403
404     ctxt = (xmlParserCtxtPtr) ctx;
405     This = (const domdoc*) ctxt->_private;
406
407     if (ctxt->node)
408     {
409         /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
410         if (!This->properties->preserving &&
411             !is_preserving_whitespace(ctxt->node) &&
412             strn_isspace(ch, len))
413             return;
414     }
415
416     xmlSAX2Characters(ctxt, ch, len);
417 }
418
419 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
420 {
421     va_list ap;
422     va_start(ap, msg);
423     LIBXML2_CALLBACK_ERR(doparse, msg, ap);
424     va_end(ap);
425 }
426
427 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
428 {
429     va_list ap;
430     va_start(ap, msg);
431     LIBXML2_CALLBACK_WARN(doparse, msg, ap);
432     va_end(ap);
433 }
434
435 static void sax_serror(void* ctx, xmlErrorPtr err)
436 {
437     LIBXML2_CALLBACK_SERROR(doparse, err);
438 }
439
440 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
441 {
442     xmlDocPtr doc = NULL;
443     xmlParserCtxtPtr pctx;
444     static xmlSAXHandler sax_handler = {
445         xmlSAX2InternalSubset,          /* internalSubset */
446         xmlSAX2IsStandalone,            /* isStandalone */
447         xmlSAX2HasInternalSubset,       /* hasInternalSubset */
448         xmlSAX2HasExternalSubset,       /* hasExternalSubset */
449         xmlSAX2ResolveEntity,           /* resolveEntity */
450         xmlSAX2GetEntity,               /* getEntity */
451         xmlSAX2EntityDecl,              /* entityDecl */
452         xmlSAX2NotationDecl,            /* notationDecl */
453         xmlSAX2AttributeDecl,           /* attributeDecl */
454         xmlSAX2ElementDecl,             /* elementDecl */
455         xmlSAX2UnparsedEntityDecl,      /* unparsedEntityDecl */
456         xmlSAX2SetDocumentLocator,      /* setDocumentLocator */
457         xmlSAX2StartDocument,           /* startDocument */
458         xmlSAX2EndDocument,             /* endDocument */
459         xmlSAX2StartElement,            /* startElement */
460         xmlSAX2EndElement,              /* endElement */
461         xmlSAX2Reference,               /* reference */
462         sax_characters,                 /* characters */
463         sax_characters,                 /* ignorableWhitespace */
464         xmlSAX2ProcessingInstruction,   /* processingInstruction */
465         xmlSAX2Comment,                 /* comment */
466         sax_warning,                    /* warning */
467         sax_error,                      /* error */
468         sax_error,                      /* fatalError */
469         xmlSAX2GetParameterEntity,      /* getParameterEntity */
470         xmlSAX2CDataBlock,              /* cdataBlock */
471         xmlSAX2ExternalSubset,          /* externalSubset */
472         0,                              /* initialized */
473         NULL,                           /* _private */
474         xmlSAX2StartElementNs,          /* startElementNs */
475         xmlSAX2EndElementNs,            /* endElementNs */
476         sax_serror                      /* serror */
477     };
478     xmlInitParser();
479
480     pctx = xmlCreateMemoryParserCtxt(ptr, len);
481     if (!pctx)
482     {
483         ERR("Failed to create parser context\n");
484         return NULL;
485     }
486
487     if (pctx->sax) xmlFree(pctx->sax);
488     pctx->sax = &sax_handler;
489     pctx->_private = This;
490     pctx->recovery = 0;
491
492     if (encoding != XML_CHAR_ENCODING_NONE)
493         xmlSwitchEncoding(pctx, encoding);
494
495     xmlParseDocument(pctx);
496
497     if (pctx->wellFormed)
498     {
499         doc = pctx->myDoc;
500     }
501     else
502     {
503        xmlFreeDoc(pctx->myDoc);
504        pctx->myDoc = NULL;
505     }
506     pctx->sax = NULL;
507     xmlFreeParserCtxt(pctx);
508
509     /* TODO: put this in one of the SAX callbacks */
510     /* create first child as a <?xml...?> */
511     if (doc && doc->standalone != -1)
512     {
513         xmlNodePtr node;
514         char buff[30];
515         xmlChar *xmlbuff = (xmlChar*)buff;
516
517         node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
518
519         /* version attribute can't be omitted */
520         sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
521         xmlNodeAddContent( node, xmlbuff );
522
523         if (doc->encoding)
524         {
525             sprintf(buff, " encoding=\"%s\"", doc->encoding);
526             xmlNodeAddContent( node, xmlbuff );
527         }
528
529         if (doc->standalone != -2)
530         {
531             sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
532             xmlNodeAddContent( node, xmlbuff );
533         }
534
535         xmldoc_link_xmldecl( doc, node );
536     }
537
538     return doc;
539 }
540
541 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
542 {
543     doc->_private = create_priv();
544     priv_from_xmlDocPtr(doc)->properties = create_properties(version);
545 }
546
547 LONG xmldoc_add_ref(xmlDocPtr doc)
548 {
549     LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
550     TRACE("(%p)->(%d)\n", doc, ref);
551     return ref;
552 }
553
554 LONG xmldoc_release(xmlDocPtr doc)
555 {
556     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
557     LONG ref = InterlockedDecrement(&priv->refs);
558     TRACE("(%p)->(%d)\n", doc, ref);
559     if(ref == 0)
560     {
561         orphan_entry *orphan, *orphan2;
562         TRACE("freeing docptr %p\n", doc);
563
564         LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
565         {
566             xmlFreeNode( orphan->node );
567             heap_free( orphan );
568         }
569         free_properties(priv->properties);
570         heap_free(doc->_private);
571
572         xmlFreeDoc(doc);
573     }
574
575     return ref;
576 }
577
578 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
579 {
580     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
581     orphan_entry *entry;
582
583     entry = heap_alloc( sizeof (*entry) );
584     if(!entry)
585         return E_OUTOFMEMORY;
586
587     entry->node = node;
588     list_add_head( &priv->orphans, &entry->entry );
589     return S_OK;
590 }
591
592 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
593 {
594     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
595     orphan_entry *entry, *entry2;
596
597     LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
598     {
599         if( entry->node == node )
600         {
601             list_remove( &entry->entry );
602             heap_free( entry );
603             return S_OK;
604         }
605     }
606
607     return S_FALSE;
608 }
609
610 static inline xmlDocPtr get_doc( domdoc *This )
611 {
612     return (xmlDocPtr)This->node.node;
613 }
614
615 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
616 {
617     if(This->node.node)
618     {
619         priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
620         if (xmldoc_release(get_doc(This)) != 0)
621             priv_from_xmlDocPtr(get_doc(This))->properties =
622                 copy_properties(This->properties);
623     }
624
625     This->node.node = (xmlNodePtr) xml;
626
627     if(This->node.node)
628     {
629         xmldoc_add_ref(get_doc(This));
630         priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
631     }
632
633     return S_OK;
634 }
635
636 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
637 {
638     return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
639 }
640
641 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
642 {
643     return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
644 }
645
646 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
647 {
648     return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
649 }
650
651 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
652 {
653     return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
654 }
655
656 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
657 {
658     return CONTAINING_RECORD(iface, domdoc, ISupportErrorInfo_iface);
659 }
660
661 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
662 {
663     return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
664 }
665
666 /************************************************************************
667  * domdoc implementation of IPersistStream.
668  */
669 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
670     IPersistStreamInit *iface, REFIID riid, void **ppvObj)
671 {
672     domdoc* This = impl_from_IPersistStreamInit(iface);
673     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
674 }
675
676 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
677     IPersistStreamInit *iface)
678 {
679     domdoc* This = impl_from_IPersistStreamInit(iface);
680     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
681 }
682
683 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
684     IPersistStreamInit *iface)
685 {
686     domdoc* This = impl_from_IPersistStreamInit(iface);
687     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
688 }
689
690 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
691     IPersistStreamInit *iface, CLSID *classid)
692 {
693     domdoc* This = impl_from_IPersistStreamInit(iface);
694     TRACE("(%p)->(%p)\n", This, classid);
695
696     if(!classid)
697         return E_POINTER;
698
699     *classid = *DOMDocument_version(This->properties->version);
700
701     return S_OK;
702 }
703
704 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
705     IPersistStreamInit *iface)
706 {
707     domdoc *This = impl_from_IPersistStreamInit(iface);
708     FIXME("(%p): stub!\n", This);
709     return S_FALSE;
710 }
711
712 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
713     IPersistStreamInit *iface, LPSTREAM pStm)
714 {
715     domdoc *This = impl_from_IPersistStreamInit(iface);
716     HRESULT hr;
717     HGLOBAL hglobal;
718     DWORD read, written, len;
719     BYTE buf[4096];
720     char *ptr;
721     xmlDocPtr xmldoc = NULL;
722
723     TRACE("(%p)->(%p)\n", This, pStm);
724
725     if (!pStm)
726         return E_INVALIDARG;
727
728     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
729     if (FAILED(hr))
730         return hr;
731
732     do
733     {
734         IStream_Read(pStm, buf, sizeof(buf), &read);
735         hr = IStream_Write(This->stream, buf, read, &written);
736     } while(SUCCEEDED(hr) && written != 0 && read != 0);
737
738     if (FAILED(hr))
739     {
740         ERR("Failed to copy stream\n");
741         return hr;
742     }
743
744     hr = GetHGlobalFromStream(This->stream, &hglobal);
745     if (FAILED(hr))
746         return hr;
747
748     len = GlobalSize(hglobal);
749     ptr = GlobalLock(hglobal);
750     if (len != 0)
751         xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
752     GlobalUnlock(hglobal);
753
754     if (!xmldoc)
755     {
756         ERR("Failed to parse xml\n");
757         return E_FAIL;
758     }
759
760     xmldoc->_private = create_priv();
761
762     return attach_xmldoc(This, xmldoc);
763 }
764
765 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
766     IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
767 {
768     domdoc *This = impl_from_IPersistStreamInit(iface);
769     BSTR xmlString;
770     HRESULT hr;
771
772     TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
773
774     hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
775     if(hr == S_OK)
776     {
777         DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
778
779         hr = IStream_Write( stream, xmlString, len, NULL );
780         SysFreeString(xmlString);
781     }
782
783     TRACE("ret 0x%08x\n", hr);
784
785     return hr;
786 }
787
788 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
789     IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
790 {
791     domdoc *This = impl_from_IPersistStreamInit(iface);
792     TRACE("(%p)->(%p): stub!\n", This, pcbSize);
793     return E_NOTIMPL;
794 }
795
796 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
797     IPersistStreamInit *iface)
798 {
799     domdoc *This = impl_from_IPersistStreamInit(iface);
800     TRACE("(%p)\n", This);
801     return S_OK;
802 }
803
804 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
805 {
806     domdoc_IPersistStreamInit_QueryInterface,
807     domdoc_IPersistStreamInit_AddRef,
808     domdoc_IPersistStreamInit_Release,
809     domdoc_IPersistStreamInit_GetClassID,
810     domdoc_IPersistStreamInit_IsDirty,
811     domdoc_IPersistStreamInit_Load,
812     domdoc_IPersistStreamInit_Save,
813     domdoc_IPersistStreamInit_GetSizeMax,
814     domdoc_IPersistStreamInit_InitNew
815 };
816
817 /* ISupportErrorInfo interface */
818 static HRESULT WINAPI support_error_QueryInterface(
819     ISupportErrorInfo *iface,
820     REFIID riid, void** ppvObj )
821 {
822     domdoc *This = impl_from_ISupportErrorInfo(iface);
823     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
824 }
825
826 static ULONG WINAPI support_error_AddRef(
827     ISupportErrorInfo *iface )
828 {
829     domdoc *This = impl_from_ISupportErrorInfo(iface);
830     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
831 }
832
833 static ULONG WINAPI support_error_Release(
834     ISupportErrorInfo *iface )
835 {
836     domdoc *This = impl_from_ISupportErrorInfo(iface);
837     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
838 }
839
840 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
841     ISupportErrorInfo *iface,
842     REFIID riid )
843 {
844     FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
845     return S_FALSE;
846 }
847
848 static const struct ISupportErrorInfoVtbl support_error_vtbl =
849 {
850     support_error_QueryInterface,
851     support_error_AddRef,
852     support_error_Release,
853     support_error_InterfaceSupportsErrorInfo
854 };
855
856 /* IXMLDOMDocument2 interface */
857 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
858 {
859     domdoc *This = impl_from_IXMLDOMDocument3( iface );
860
861     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
862
863     *ppvObject = NULL;
864
865     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
866          IsEqualGUID( riid, &IID_IDispatch ) ||
867          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
868          IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
869          IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
870          IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
871     {
872         *ppvObject = iface;
873     }
874     else if (IsEqualGUID(&IID_IPersistStream, riid) ||
875              IsEqualGUID(&IID_IPersistStreamInit, riid))
876     {
877         *ppvObject = &This->IPersistStreamInit_iface;
878     }
879     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
880     {
881         *ppvObject = &This->IObjectWithSite_iface;
882     }
883     else if (IsEqualGUID(&IID_IObjectSafety, riid))
884     {
885         *ppvObject = &This->IObjectSafety_iface;
886     }
887     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
888     {
889         *ppvObject = &This->ISupportErrorInfo_iface;
890     }
891     else if(node_query_interface(&This->node, riid, ppvObject))
892     {
893         return *ppvObject ? S_OK : E_NOINTERFACE;
894     }
895     else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
896     {
897         *ppvObject = &This->IConnectionPointContainer_iface;
898     }
899     else
900     {
901         TRACE("interface %s not implemented\n", debugstr_guid(riid));
902         return E_NOINTERFACE;
903     }
904
905     IUnknown_AddRef((IUnknown*)*ppvObject);
906
907     return S_OK;
908 }
909
910
911 static ULONG WINAPI domdoc_AddRef(
912      IXMLDOMDocument3 *iface )
913 {
914     domdoc *This = impl_from_IXMLDOMDocument3( iface );
915     ULONG ref = InterlockedIncrement( &This->ref );
916     TRACE("(%p)->(%d)\n", This, ref );
917     return ref;
918 }
919
920
921 static ULONG WINAPI domdoc_Release(
922      IXMLDOMDocument3 *iface )
923 {
924     domdoc *This = impl_from_IXMLDOMDocument3( iface );
925     LONG ref = InterlockedDecrement( &This->ref );
926
927     TRACE("(%p)->(%d)\n", This, ref );
928
929     if ( ref == 0 )
930     {
931         int eid;
932
933         if(This->bsc)
934             detach_bsc(This->bsc);
935
936         if (This->site)
937             IUnknown_Release( This->site );
938         destroy_xmlnode(&This->node);
939         if (This->stream)
940             IStream_Release(This->stream);
941
942         for (eid = 0; eid < EVENTID_LAST; eid++)
943             if (This->events[eid]) IDispatch_Release(This->events[eid]);
944
945         heap_free(This);
946     }
947
948     return ref;
949 }
950
951 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
952 {
953     domdoc *This = impl_from_IXMLDOMDocument3( iface );
954
955     TRACE("(%p)->(%p)\n", This, pctinfo);
956
957     *pctinfo = 1;
958
959     return S_OK;
960 }
961
962 static HRESULT WINAPI domdoc_GetTypeInfo(
963     IXMLDOMDocument3 *iface,
964     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
965 {
966     domdoc *This = impl_from_IXMLDOMDocument3( iface );
967     HRESULT hr;
968
969     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
970
971     hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
972
973     return hr;
974 }
975
976 static HRESULT WINAPI domdoc_GetIDsOfNames(
977     IXMLDOMDocument3 *iface,
978     REFIID riid,
979     LPOLESTR* rgszNames,
980     UINT cNames,
981     LCID lcid,
982     DISPID* rgDispId)
983 {
984     domdoc *This = impl_from_IXMLDOMDocument3( iface );
985     ITypeInfo *typeinfo;
986     HRESULT hr;
987
988     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
989           lcid, rgDispId);
990
991     if(!rgszNames || cNames == 0 || !rgDispId)
992         return E_INVALIDARG;
993
994     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
995     if(SUCCEEDED(hr))
996     {
997         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
998         ITypeInfo_Release(typeinfo);
999     }
1000
1001     return hr;
1002 }
1003
1004
1005 static HRESULT WINAPI domdoc_Invoke(
1006     IXMLDOMDocument3 *iface,
1007     DISPID dispIdMember,
1008     REFIID riid,
1009     LCID lcid,
1010     WORD wFlags,
1011     DISPPARAMS* pDispParams,
1012     VARIANT* pVarResult,
1013     EXCEPINFO* pExcepInfo,
1014     UINT* puArgErr)
1015 {
1016     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017     ITypeInfo *typeinfo;
1018     HRESULT hr;
1019
1020     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1021           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1022
1023     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1024     if(SUCCEEDED(hr))
1025     {
1026         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMDocument3_iface, dispIdMember, wFlags,
1027                 pDispParams, pVarResult, pExcepInfo, puArgErr);
1028         ITypeInfo_Release(typeinfo);
1029     }
1030
1031     return hr;
1032 }
1033
1034
1035 static HRESULT WINAPI domdoc_get_nodeName(
1036     IXMLDOMDocument3 *iface,
1037     BSTR* name )
1038 {
1039     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1040
1041     static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1042
1043     TRACE("(%p)->(%p)\n", This, name);
1044
1045     return return_bstr(documentW, name);
1046 }
1047
1048
1049 static HRESULT WINAPI domdoc_get_nodeValue(
1050     IXMLDOMDocument3 *iface,
1051     VARIANT* value )
1052 {
1053     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1054
1055     TRACE("(%p)->(%p)\n", This, value);
1056
1057     if(!value)
1058         return E_INVALIDARG;
1059
1060     V_VT(value) = VT_NULL;
1061     V_BSTR(value) = NULL; /* tests show that we should do this */
1062     return S_FALSE;
1063 }
1064
1065
1066 static HRESULT WINAPI domdoc_put_nodeValue(
1067     IXMLDOMDocument3 *iface,
1068     VARIANT value)
1069 {
1070     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1071     TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1072     return E_FAIL;
1073 }
1074
1075
1076 static HRESULT WINAPI domdoc_get_nodeType(
1077     IXMLDOMDocument3 *iface,
1078     DOMNodeType* type )
1079 {
1080     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1081
1082     TRACE("(%p)->(%p)\n", This, type);
1083
1084     *type = NODE_DOCUMENT;
1085     return S_OK;
1086 }
1087
1088
1089 static HRESULT WINAPI domdoc_get_parentNode(
1090     IXMLDOMDocument3 *iface,
1091     IXMLDOMNode** parent )
1092 {
1093     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1094
1095     TRACE("(%p)->(%p)\n", This, parent);
1096
1097     return node_get_parent(&This->node, parent);
1098 }
1099
1100
1101 static HRESULT WINAPI domdoc_get_childNodes(
1102     IXMLDOMDocument3 *iface,
1103     IXMLDOMNodeList** childList )
1104 {
1105     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1106
1107     TRACE("(%p)->(%p)\n", This, childList);
1108
1109     return node_get_child_nodes(&This->node, childList);
1110 }
1111
1112
1113 static HRESULT WINAPI domdoc_get_firstChild(
1114     IXMLDOMDocument3 *iface,
1115     IXMLDOMNode** firstChild )
1116 {
1117     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1118
1119     TRACE("(%p)->(%p)\n", This, firstChild);
1120
1121     return node_get_first_child(&This->node, firstChild);
1122 }
1123
1124
1125 static HRESULT WINAPI domdoc_get_lastChild(
1126     IXMLDOMDocument3 *iface,
1127     IXMLDOMNode** lastChild )
1128 {
1129     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130
1131     TRACE("(%p)->(%p)\n", This, lastChild);
1132
1133     return node_get_last_child(&This->node, lastChild);
1134 }
1135
1136
1137 static HRESULT WINAPI domdoc_get_previousSibling(
1138     IXMLDOMDocument3 *iface,
1139     IXMLDOMNode** previousSibling )
1140 {
1141     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142
1143     TRACE("(%p)->(%p)\n", This, previousSibling);
1144
1145     return return_null_node(previousSibling);
1146 }
1147
1148
1149 static HRESULT WINAPI domdoc_get_nextSibling(
1150     IXMLDOMDocument3 *iface,
1151     IXMLDOMNode** nextSibling )
1152 {
1153     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1154
1155     TRACE("(%p)->(%p)\n", This, nextSibling);
1156
1157     return return_null_node(nextSibling);
1158 }
1159
1160
1161 static HRESULT WINAPI domdoc_get_attributes(
1162     IXMLDOMDocument3 *iface,
1163     IXMLDOMNamedNodeMap** attributeMap )
1164 {
1165     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1166
1167     TRACE("(%p)->(%p)\n", This, attributeMap);
1168
1169     return return_null_ptr((void**)attributeMap);
1170 }
1171
1172
1173 static HRESULT WINAPI domdoc_insertBefore(
1174     IXMLDOMDocument3 *iface,
1175     IXMLDOMNode* newChild,
1176     VARIANT refChild,
1177     IXMLDOMNode** outNewChild )
1178 {
1179     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1180
1181     TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1182
1183     return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1184 }
1185
1186
1187 static HRESULT WINAPI domdoc_replaceChild(
1188     IXMLDOMDocument3 *iface,
1189     IXMLDOMNode* newChild,
1190     IXMLDOMNode* oldChild,
1191     IXMLDOMNode** outOldChild)
1192 {
1193     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194
1195     TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1196
1197     return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1198 }
1199
1200
1201 static HRESULT WINAPI domdoc_removeChild(
1202     IXMLDOMDocument3 *iface,
1203     IXMLDOMNode  *child,
1204     IXMLDOMNode **oldChild)
1205 {
1206     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1207     TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1208     return node_remove_child(&This->node, child, oldChild);
1209 }
1210
1211
1212 static HRESULT WINAPI domdoc_appendChild(
1213     IXMLDOMDocument3 *iface,
1214     IXMLDOMNode  *child,
1215     IXMLDOMNode **outChild)
1216 {
1217     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1218     TRACE("(%p)->(%p %p)\n", This, child, outChild);
1219     return node_append_child(&This->node, child, outChild);
1220 }
1221
1222
1223 static HRESULT WINAPI domdoc_hasChildNodes(
1224     IXMLDOMDocument3 *iface,
1225     VARIANT_BOOL *ret)
1226 {
1227     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1228     TRACE("(%p)->(%p)\n", This, ret);
1229     return node_has_childnodes(&This->node, ret);
1230 }
1231
1232
1233 static HRESULT WINAPI domdoc_get_ownerDocument(
1234     IXMLDOMDocument3 *iface,
1235     IXMLDOMDocument **doc)
1236 {
1237     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1238     TRACE("(%p)->(%p)\n", This, doc);
1239     return node_get_owner_doc(&This->node, doc);
1240 }
1241
1242
1243 static HRESULT WINAPI domdoc_cloneNode(
1244     IXMLDOMDocument3 *iface,
1245     VARIANT_BOOL deep,
1246     IXMLDOMNode** outNode)
1247 {
1248     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1249     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1250     return node_clone( &This->node, deep, outNode );
1251 }
1252
1253
1254 static HRESULT WINAPI domdoc_get_nodeTypeString(
1255     IXMLDOMDocument3 *iface,
1256     BSTR *p)
1257 {
1258     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1259     static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1260
1261     TRACE("(%p)->(%p)\n", This, p);
1262
1263     return return_bstr(documentW, p);
1264 }
1265
1266
1267 static HRESULT WINAPI domdoc_get_text(
1268     IXMLDOMDocument3 *iface,
1269     BSTR *p)
1270 {
1271     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1272     TRACE("(%p)->(%p)\n", This, p);
1273     return node_get_text(&This->node, p);
1274 }
1275
1276
1277 static HRESULT WINAPI domdoc_put_text(
1278     IXMLDOMDocument3 *iface,
1279     BSTR text )
1280 {
1281     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1282     TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1283     return E_FAIL;
1284 }
1285
1286
1287 static HRESULT WINAPI domdoc_get_specified(
1288     IXMLDOMDocument3 *iface,
1289     VARIANT_BOOL* isSpecified )
1290 {
1291     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1292     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1293     *isSpecified = VARIANT_TRUE;
1294     return S_OK;
1295 }
1296
1297
1298 static HRESULT WINAPI domdoc_get_definition(
1299     IXMLDOMDocument3 *iface,
1300     IXMLDOMNode** definitionNode )
1301 {
1302     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1303     FIXME("(%p)->(%p)\n", This, definitionNode);
1304     return E_NOTIMPL;
1305 }
1306
1307
1308 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1309     IXMLDOMDocument3 *iface,
1310     VARIANT* v )
1311 {
1312     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313     TRACE("(%p)->(%p)\n", This, v);
1314     return return_null_var(v);
1315 }
1316
1317 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1318     IXMLDOMDocument3 *iface,
1319     VARIANT typedValue )
1320 {
1321     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1322     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1323     return E_NOTIMPL;
1324 }
1325
1326
1327 static HRESULT WINAPI domdoc_get_dataType(
1328     IXMLDOMDocument3 *iface,
1329     VARIANT* typename )
1330 {
1331     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1332     TRACE("(%p)->(%p)\n", This, typename);
1333     return return_null_var( typename );
1334 }
1335
1336
1337 static HRESULT WINAPI domdoc_put_dataType(
1338     IXMLDOMDocument3 *iface,
1339     BSTR dataTypeName )
1340 {
1341     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1342
1343     FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1344
1345     if(!dataTypeName)
1346         return E_INVALIDARG;
1347
1348     return E_FAIL;
1349 }
1350
1351 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1352 {
1353     return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1354 }
1355
1356 static HRESULT WINAPI domdoc_get_xml(
1357     IXMLDOMDocument3 *iface,
1358     BSTR* p)
1359 {
1360     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1361     xmlSaveCtxtPtr ctxt;
1362     xmlBufferPtr buf;
1363     int options;
1364     long ret;
1365
1366     TRACE("(%p)->(%p)\n", This, p);
1367
1368     if(!p)
1369         return E_INVALIDARG;
1370
1371     *p = NULL;
1372
1373     buf = xmlBufferCreate();
1374     if(!buf)
1375         return E_OUTOFMEMORY;
1376
1377     options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1378     ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1379
1380     if(!ctxt)
1381     {
1382         xmlBufferFree(buf);
1383         return E_OUTOFMEMORY;
1384     }
1385
1386     ret = xmlSaveDoc(ctxt, get_doc(This));
1387     /* flushes on close */
1388     xmlSaveClose(ctxt);
1389
1390     TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1391     if(ret != -1 && xmlBufferLength(buf) > 0)
1392     {
1393         BSTR content;
1394
1395         content = bstr_from_xmlChar(xmlBufferContent(buf));
1396         content = EnsureCorrectEOL(content);
1397
1398         *p = content;
1399     }
1400     else
1401     {
1402         *p = SysAllocStringLen(NULL, 0);
1403     }
1404
1405     xmlBufferFree(buf);
1406
1407     return *p ? S_OK : E_OUTOFMEMORY;
1408 }
1409
1410
1411 static HRESULT WINAPI domdoc_transformNode(
1412     IXMLDOMDocument3 *iface,
1413     IXMLDOMNode *node,
1414     BSTR *p)
1415 {
1416     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1417     TRACE("(%p)->(%p %p)\n", This, node, p);
1418     return node_transform_node(&This->node, node, p);
1419 }
1420
1421
1422 static HRESULT WINAPI domdoc_selectNodes(
1423     IXMLDOMDocument3 *iface,
1424     BSTR p,
1425     IXMLDOMNodeList **outList)
1426 {
1427     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1428     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1429     return node_select_nodes(&This->node, p, outList);
1430 }
1431
1432
1433 static HRESULT WINAPI domdoc_selectSingleNode(
1434     IXMLDOMDocument3 *iface,
1435     BSTR p,
1436     IXMLDOMNode **outNode)
1437 {
1438     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1439     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1440     return node_select_singlenode(&This->node, p, outNode);
1441 }
1442
1443
1444 static HRESULT WINAPI domdoc_get_parsed(
1445     IXMLDOMDocument3 *iface,
1446     VARIANT_BOOL* isParsed )
1447 {
1448     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1449     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1450     *isParsed = VARIANT_TRUE;
1451     return S_OK;
1452 }
1453
1454
1455 static HRESULT WINAPI domdoc_get_namespaceURI(
1456     IXMLDOMDocument3 *iface,
1457     BSTR* namespaceURI )
1458 {
1459     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460     TRACE("(%p)->(%p)\n", This, namespaceURI);
1461     return node_get_namespaceURI(&This->node, namespaceURI);
1462 }
1463
1464
1465 static HRESULT WINAPI domdoc_get_prefix(
1466     IXMLDOMDocument3 *iface,
1467     BSTR* prefix )
1468 {
1469     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1470     TRACE("(%p)->(%p)\n", This, prefix);
1471     return return_null_bstr( prefix );
1472 }
1473
1474
1475 static HRESULT WINAPI domdoc_get_baseName(
1476     IXMLDOMDocument3 *iface,
1477     BSTR* name )
1478 {
1479     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1480     TRACE("(%p)->(%p)\n", This, name);
1481     return return_null_bstr( name );
1482 }
1483
1484
1485 static HRESULT WINAPI domdoc_transformNodeToObject(
1486     IXMLDOMDocument3 *iface,
1487     IXMLDOMNode* stylesheet,
1488     VARIANT outputObject)
1489 {
1490     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1491     FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1492     return E_NOTIMPL;
1493 }
1494
1495
1496 static HRESULT WINAPI domdoc_get_doctype(
1497     IXMLDOMDocument3 *iface,
1498     IXMLDOMDocumentType** doctype )
1499 {
1500     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1501     IXMLDOMNode *node;
1502     xmlDtdPtr dtd;
1503     HRESULT hr;
1504
1505     TRACE("(%p)->(%p)\n", This, doctype);
1506
1507     if (!doctype) return E_INVALIDARG;
1508
1509     *doctype = NULL;
1510
1511     dtd = xmlGetIntSubset(get_doc(This));
1512     if (!dtd) return S_FALSE;
1513
1514     node = create_node((xmlNodePtr)dtd);
1515     if (!node) return S_FALSE;
1516
1517     hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1518     IXMLDOMNode_Release(node);
1519
1520     return hr;
1521 }
1522
1523
1524 static HRESULT WINAPI domdoc_get_implementation(
1525     IXMLDOMDocument3 *iface,
1526     IXMLDOMImplementation** impl )
1527 {
1528     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1529
1530     TRACE("(%p)->(%p)\n", This, impl);
1531
1532     if(!impl)
1533         return E_INVALIDARG;
1534
1535     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1536
1537     return S_OK;
1538 }
1539
1540 static HRESULT WINAPI domdoc_get_documentElement(
1541     IXMLDOMDocument3 *iface,
1542     IXMLDOMElement** DOMElement )
1543 {
1544     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1545     IXMLDOMNode *element_node;
1546     xmlNodePtr root;
1547     HRESULT hr;
1548
1549     TRACE("(%p)->(%p)\n", This, DOMElement);
1550
1551     if(!DOMElement)
1552         return E_INVALIDARG;
1553
1554     *DOMElement = NULL;
1555
1556     root = xmlDocGetRootElement( get_doc(This) );
1557     if ( !root )
1558         return S_FALSE;
1559
1560     element_node = create_node( root );
1561     if(!element_node) return S_FALSE;
1562
1563     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1564     IXMLDOMNode_Release(element_node);
1565
1566     return hr;
1567 }
1568
1569
1570 static HRESULT WINAPI domdoc_put_documentElement(
1571     IXMLDOMDocument3 *iface,
1572     IXMLDOMElement* DOMElement )
1573 {
1574     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1575     IXMLDOMNode *elementNode;
1576     xmlNodePtr oldRoot;
1577     xmlnode *xmlNode;
1578     HRESULT hr;
1579
1580     TRACE("(%p)->(%p)\n", This, DOMElement);
1581
1582     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1583     if(FAILED(hr))
1584         return hr;
1585
1586     xmlNode = get_node_obj( elementNode );
1587     if(!xmlNode) return E_FAIL;
1588
1589     if(!xmlNode->node->parent)
1590         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1591             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1592
1593     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1594     IXMLDOMNode_Release( elementNode );
1595
1596     if(oldRoot)
1597         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1598
1599     return S_OK;
1600 }
1601
1602
1603 static HRESULT WINAPI domdoc_createElement(
1604     IXMLDOMDocument3 *iface,
1605     BSTR tagname,
1606     IXMLDOMElement** element )
1607 {
1608     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1609     IXMLDOMNode *node;
1610     VARIANT type;
1611     HRESULT hr;
1612
1613     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1614
1615     if (!element || !tagname) return E_INVALIDARG;
1616
1617     V_VT(&type) = VT_I1;
1618     V_I1(&type) = NODE_ELEMENT;
1619
1620     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1621     if (hr == S_OK)
1622     {
1623         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1624         IXMLDOMNode_Release(node);
1625     }
1626
1627     return hr;
1628 }
1629
1630
1631 static HRESULT WINAPI domdoc_createDocumentFragment(
1632     IXMLDOMDocument3 *iface,
1633     IXMLDOMDocumentFragment** frag )
1634 {
1635     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1636     IXMLDOMNode *node;
1637     VARIANT type;
1638     HRESULT hr;
1639
1640     TRACE("(%p)->(%p)\n", This, frag);
1641
1642     if (!frag) return E_INVALIDARG;
1643
1644     *frag = NULL;
1645
1646     V_VT(&type) = VT_I1;
1647     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1648
1649     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1650     if (hr == S_OK)
1651     {
1652         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1653         IXMLDOMNode_Release(node);
1654     }
1655
1656     return hr;
1657 }
1658
1659
1660 static HRESULT WINAPI domdoc_createTextNode(
1661     IXMLDOMDocument3 *iface,
1662     BSTR data,
1663     IXMLDOMText** text )
1664 {
1665     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1666     IXMLDOMNode *node;
1667     VARIANT type;
1668     HRESULT hr;
1669
1670     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1671
1672     if (!text) return E_INVALIDARG;
1673
1674     *text = NULL;
1675
1676     V_VT(&type) = VT_I1;
1677     V_I1(&type) = NODE_TEXT;
1678
1679     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1680     if (hr == S_OK)
1681     {
1682         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1683         IXMLDOMNode_Release(node);
1684         hr = IXMLDOMText_put_data(*text, data);
1685     }
1686
1687     return hr;
1688 }
1689
1690
1691 static HRESULT WINAPI domdoc_createComment(
1692     IXMLDOMDocument3 *iface,
1693     BSTR data,
1694     IXMLDOMComment** comment )
1695 {
1696     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1697     VARIANT type;
1698     HRESULT hr;
1699     IXMLDOMNode *node;
1700
1701     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1702
1703     if (!comment) return E_INVALIDARG;
1704
1705     *comment = NULL;
1706
1707     V_VT(&type) = VT_I1;
1708     V_I1(&type) = NODE_COMMENT;
1709
1710     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1711     if (hr == S_OK)
1712     {
1713         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1714         IXMLDOMNode_Release(node);
1715         hr = IXMLDOMComment_put_data(*comment, data);
1716     }
1717
1718     return hr;
1719 }
1720
1721
1722 static HRESULT WINAPI domdoc_createCDATASection(
1723     IXMLDOMDocument3 *iface,
1724     BSTR data,
1725     IXMLDOMCDATASection** cdata )
1726 {
1727     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1728     IXMLDOMNode *node;
1729     VARIANT type;
1730     HRESULT hr;
1731
1732     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1733
1734     if (!cdata) return E_INVALIDARG;
1735
1736     *cdata = NULL;
1737
1738     V_VT(&type) = VT_I1;
1739     V_I1(&type) = NODE_CDATA_SECTION;
1740
1741     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1742     if (hr == S_OK)
1743     {
1744         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1745         IXMLDOMNode_Release(node);
1746         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1747     }
1748
1749     return hr;
1750 }
1751
1752
1753 static HRESULT WINAPI domdoc_createProcessingInstruction(
1754     IXMLDOMDocument3 *iface,
1755     BSTR target,
1756     BSTR data,
1757     IXMLDOMProcessingInstruction** pi )
1758 {
1759     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1760     IXMLDOMNode *node;
1761     VARIANT type;
1762     HRESULT hr;
1763
1764     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1765
1766     if (!pi) return E_INVALIDARG;
1767
1768     *pi = NULL;
1769
1770     V_VT(&type) = VT_I1;
1771     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1772
1773     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1774     if (hr == S_OK)
1775     {
1776         xmlnode *node_obj;
1777
1778         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1779         node_obj = get_node_obj(node);
1780         hr = node_set_content(node_obj, data);
1781
1782         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1783         IXMLDOMNode_Release(node);
1784     }
1785
1786     return hr;
1787 }
1788
1789
1790 static HRESULT WINAPI domdoc_createAttribute(
1791     IXMLDOMDocument3 *iface,
1792     BSTR name,
1793     IXMLDOMAttribute** attribute )
1794 {
1795     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1796     IXMLDOMNode *node;
1797     VARIANT type;
1798     HRESULT hr;
1799
1800     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1801
1802     if (!attribute || !name) return E_INVALIDARG;
1803
1804     V_VT(&type) = VT_I1;
1805     V_I1(&type) = NODE_ATTRIBUTE;
1806
1807     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1808     if (hr == S_OK)
1809     {
1810         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1811         IXMLDOMNode_Release(node);
1812     }
1813
1814     return hr;
1815 }
1816
1817
1818 static HRESULT WINAPI domdoc_createEntityReference(
1819     IXMLDOMDocument3 *iface,
1820     BSTR name,
1821     IXMLDOMEntityReference** entityref )
1822 {
1823     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1824     IXMLDOMNode *node;
1825     VARIANT type;
1826     HRESULT hr;
1827
1828     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1829
1830     if (!entityref) return E_INVALIDARG;
1831
1832     *entityref = NULL;
1833
1834     V_VT(&type) = VT_I1;
1835     V_I1(&type) = NODE_ENTITY_REFERENCE;
1836
1837     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1838     if (hr == S_OK)
1839     {
1840         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1841         IXMLDOMNode_Release(node);
1842     }
1843
1844     return hr;
1845 }
1846
1847 xmlChar* tagName_to_XPath(const BSTR tagName)
1848 {
1849     xmlChar *query, *tmp;
1850     static const xmlChar mod_pre[] = "*[local-name()='";
1851     static const xmlChar mod_post[] = "']";
1852     static const xmlChar prefix[] = "descendant::";
1853     const WCHAR *tokBegin, *tokEnd;
1854     int len;
1855
1856     query = xmlStrdup(prefix);
1857
1858     tokBegin = tagName;
1859     while (tokBegin && *tokBegin)
1860     {
1861         switch (*tokBegin)
1862         {
1863         case '/':
1864             query = xmlStrcat(query, BAD_CAST "/");
1865             ++tokBegin;
1866             break;
1867         case '*':
1868             query = xmlStrcat(query, BAD_CAST "*");
1869             ++tokBegin;
1870             break;
1871         default:
1872             query = xmlStrcat(query, mod_pre);
1873             tokEnd = tokBegin;
1874             while (*tokEnd && *tokEnd != '/')
1875                 ++tokEnd;
1876             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1877             tmp = xmlMalloc(len);
1878             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1879             query = xmlStrncat(query, tmp, len);
1880             xmlFree(tmp);
1881             tokBegin = tokEnd;
1882             query = xmlStrcat(query, mod_post);
1883         }
1884     }
1885
1886     return query;
1887 }
1888
1889 static HRESULT WINAPI domdoc_getElementsByTagName(
1890     IXMLDOMDocument3 *iface,
1891     BSTR tagName,
1892     IXMLDOMNodeList** resultList )
1893 {
1894     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1895     xmlChar *query;
1896     HRESULT hr;
1897     BOOL XPath;
1898
1899     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1900
1901     if (!tagName || !resultList) return E_INVALIDARG;
1902
1903     XPath = This->properties->XPath;
1904     This->properties->XPath = TRUE;
1905     query = tagName_to_XPath(tagName);
1906     hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1907     xmlFree(query);
1908     This->properties->XPath = XPath;
1909
1910     return hr;
1911 }
1912
1913 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1914 {
1915     VARIANT tmp;
1916     HRESULT hr;
1917
1918     VariantInit(&tmp);
1919     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1920     if(FAILED(hr))
1921         return E_INVALIDARG;
1922
1923     *type = V_I4(&tmp);
1924
1925     return S_OK;
1926 }
1927
1928 static HRESULT WINAPI domdoc_createNode(
1929     IXMLDOMDocument3 *iface,
1930     VARIANT Type,
1931     BSTR name,
1932     BSTR namespaceURI,
1933     IXMLDOMNode** node )
1934 {
1935     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1936     DOMNodeType node_type;
1937     xmlNodePtr xmlnode;
1938     xmlChar *xml_name, *href;
1939     HRESULT hr;
1940
1941     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1942
1943     if(!node) return E_INVALIDARG;
1944
1945     hr = get_node_type(Type, &node_type);
1946     if(FAILED(hr)) return hr;
1947
1948     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1949         FIXME("nodes with namespaces currently not supported.\n");
1950
1951     TRACE("node_type %d\n", node_type);
1952
1953     /* exit earlier for types that need name */
1954     switch(node_type)
1955     {
1956     case NODE_ELEMENT:
1957     case NODE_ATTRIBUTE:
1958     case NODE_ENTITY_REFERENCE:
1959     case NODE_PROCESSING_INSTRUCTION:
1960         if (!name || *name == 0) return E_FAIL;
1961         break;
1962     default:
1963         break;
1964     }
1965
1966     xml_name = xmlchar_from_wchar(name);
1967     /* prevent empty href to be allocated */
1968     href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1969
1970     switch(node_type)
1971     {
1972     case NODE_ELEMENT:
1973     {
1974         xmlChar *local, *prefix;
1975
1976         local = xmlSplitQName2(xml_name, &prefix);
1977
1978         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1979
1980         /* allow to create default namespace xmlns= */
1981         if (local || (href && *href))
1982         {
1983             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1984             xmlSetNs(xmlnode, ns);
1985         }
1986
1987         xmlFree(local);
1988         xmlFree(prefix);
1989
1990         break;
1991     }
1992     case NODE_ATTRIBUTE:
1993         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1994         break;
1995     case NODE_TEXT:
1996         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1997         break;
1998     case NODE_CDATA_SECTION:
1999         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2000         break;
2001     case NODE_ENTITY_REFERENCE:
2002         xmlnode = xmlNewReference(get_doc(This), xml_name);
2003         break;
2004     case NODE_PROCESSING_INSTRUCTION:
2005 #ifdef HAVE_XMLNEWDOCPI
2006         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2007 #else
2008         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2009         xmlnode = NULL;
2010 #endif
2011         break;
2012     case NODE_COMMENT:
2013         xmlnode = xmlNewDocComment(get_doc(This), NULL);
2014         break;
2015     case NODE_DOCUMENT_FRAGMENT:
2016         xmlnode = xmlNewDocFragment(get_doc(This));
2017         break;
2018     /* unsupported types */
2019     case NODE_DOCUMENT:
2020     case NODE_DOCUMENT_TYPE:
2021     case NODE_ENTITY:
2022     case NODE_NOTATION:
2023         heap_free(xml_name);
2024         return E_INVALIDARG;
2025     default:
2026         FIXME("unhandled node type %d\n", node_type);
2027         xmlnode = NULL;
2028         break;
2029     }
2030
2031     *node = create_node(xmlnode);
2032     heap_free(xml_name);
2033     heap_free(href);
2034
2035     if(*node)
2036     {
2037         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2038         xmldoc_add_orphan(xmlnode->doc, xmlnode);
2039         return S_OK;
2040     }
2041
2042     return E_FAIL;
2043 }
2044
2045 static HRESULT WINAPI domdoc_nodeFromID(
2046     IXMLDOMDocument3 *iface,
2047     BSTR idString,
2048     IXMLDOMNode** node )
2049 {
2050     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2051     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2052     return E_NOTIMPL;
2053 }
2054
2055 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2056 {
2057     domdoc *This = obj;
2058     xmlDocPtr xmldoc;
2059
2060     xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2061     if(xmldoc) {
2062         xmldoc->_private = create_priv();
2063         return attach_xmldoc(This, xmldoc);
2064     }
2065
2066     return S_OK;
2067 }
2068
2069 static HRESULT doread( domdoc *This, LPWSTR filename )
2070 {
2071     bsc_t *bsc;
2072     HRESULT hr;
2073
2074     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2075     if(FAILED(hr))
2076         return hr;
2077
2078     if(This->bsc)
2079         detach_bsc(This->bsc);
2080
2081     This->bsc = bsc;
2082     return S_OK;
2083 }
2084
2085 static HRESULT WINAPI domdoc_load(
2086     IXMLDOMDocument3 *iface,
2087     VARIANT source,
2088     VARIANT_BOOL* isSuccessful )
2089 {
2090     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2091     LPWSTR filename = NULL;
2092     HRESULT hr = S_FALSE;
2093     IXMLDOMDocument3 *pNewDoc = NULL;
2094     IStream *pStream = NULL;
2095     xmlDocPtr xmldoc;
2096
2097     TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2098
2099     if (!isSuccessful)
2100         return E_POINTER;
2101     *isSuccessful = VARIANT_FALSE;
2102
2103     assert( &This->node );
2104
2105     switch( V_VT(&source) )
2106     {
2107     case VT_BSTR:
2108         filename = V_BSTR(&source);
2109         break;
2110     case VT_BSTR|VT_BYREF:
2111         if (!V_BSTRREF(&source)) return E_INVALIDARG;
2112         filename = *V_BSTRREF(&source);
2113         break;
2114     case VT_ARRAY|VT_UI1:
2115         {
2116             SAFEARRAY *psa = V_ARRAY(&source);
2117             char *str;
2118             LONG len;
2119             UINT dim = SafeArrayGetDim(psa);
2120
2121             switch (dim)
2122             {
2123             case 0:
2124                 ERR("SAFEARRAY == NULL\n");
2125                 hr = This->error = E_INVALIDARG;
2126                 break;
2127             case 1:
2128                 /* Only takes UTF-8 strings.
2129                  * NOT NULL-terminated. */
2130                 SafeArrayAccessData(psa, (void**)&str);
2131                 SafeArrayGetUBound(psa, 1, &len);
2132
2133                 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2134                 {
2135                     hr = This->error = S_OK;
2136                     *isSuccessful = VARIANT_TRUE;
2137                     TRACE("parsed document %p\n", xmldoc);
2138                 }
2139                 else
2140                 {
2141                     This->error = E_FAIL;
2142                     TRACE("failed to parse document\n");
2143                 }
2144
2145                 SafeArrayUnaccessData(psa);
2146
2147                 if(xmldoc)
2148                 {
2149                     xmldoc->_private = create_priv();
2150                     return attach_xmldoc(This, xmldoc);
2151                 }
2152                 break;
2153             default:
2154                 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2155                 hr = This->error = E_NOTIMPL;
2156             }
2157         }
2158         break;
2159     case VT_UNKNOWN:
2160         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2161         if(hr == S_OK)
2162         {
2163             if(pNewDoc)
2164             {
2165                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2166                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2167                 hr = attach_xmldoc(This, xmldoc);
2168
2169                 if(SUCCEEDED(hr))
2170                     *isSuccessful = VARIANT_TRUE;
2171
2172                 return hr;
2173             }
2174         }
2175         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2176         if(hr == S_OK)
2177         {
2178             IPersistStream *pDocStream;
2179             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2180             if(hr == S_OK)
2181             {
2182                 hr = IPersistStream_Load(pDocStream, pStream);
2183                 IStream_Release(pStream);
2184                 if(hr == S_OK)
2185                 {
2186                     *isSuccessful = VARIANT_TRUE;
2187
2188                     TRACE("Using IStream to load Document\n");
2189                     return S_OK;
2190                 }
2191                 else
2192                 {
2193                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2194                 }
2195             }
2196             else
2197             {
2198                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2199             }
2200         }
2201         else
2202         {
2203             /* ISequentialStream */
2204             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2205         }
2206         break;
2207      default:
2208             FIXME("VT type not supported (%d)\n", V_VT(&source));
2209     }
2210
2211     if ( filename )
2212     {
2213         hr = doread( This, filename );
2214
2215         if ( FAILED(hr) )
2216             This->error = E_FAIL;
2217         else
2218         {
2219             hr = This->error = S_OK;
2220             *isSuccessful = VARIANT_TRUE;
2221         }
2222     }
2223
2224     if(!filename || FAILED(hr)) {
2225         xmldoc = xmlNewDoc(NULL);
2226         xmldoc->_private = create_priv();
2227         hr = attach_xmldoc(This, xmldoc);
2228         if(SUCCEEDED(hr))
2229             hr = S_FALSE;
2230     }
2231
2232     TRACE("ret (%d)\n", hr);
2233
2234     return hr;
2235 }
2236
2237
2238 static HRESULT WINAPI domdoc_get_readyState(
2239     IXMLDOMDocument3 *iface,
2240     LONG *value )
2241 {
2242     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2243     FIXME("stub! (%p)->(%p)\n", This, value);
2244
2245     if (!value)
2246         return E_INVALIDARG;
2247
2248     *value = READYSTATE_COMPLETE;
2249     return S_OK;
2250 }
2251
2252
2253 static HRESULT WINAPI domdoc_get_parseError(
2254     IXMLDOMDocument3 *iface,
2255     IXMLDOMParseError** errorObj )
2256 {
2257     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2258     static const WCHAR err[] = {'e','r','r','o','r',0};
2259     BSTR error_string = NULL;
2260
2261     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2262
2263     if(This->error)
2264         error_string = SysAllocString(err);
2265
2266     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2267     if(!*errorObj) return E_OUTOFMEMORY;
2268     return S_OK;
2269 }
2270
2271
2272 static HRESULT WINAPI domdoc_get_url(
2273     IXMLDOMDocument3 *iface,
2274     BSTR* urlString )
2275 {
2276     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2277     FIXME("(%p)->(%p)\n", This, urlString);
2278     return E_NOTIMPL;
2279 }
2280
2281
2282 static HRESULT WINAPI domdoc_get_async(
2283     IXMLDOMDocument3 *iface,
2284     VARIANT_BOOL* isAsync )
2285 {
2286     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2287
2288     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2289     *isAsync = This->async;
2290     return S_OK;
2291 }
2292
2293
2294 static HRESULT WINAPI domdoc_put_async(
2295     IXMLDOMDocument3 *iface,
2296     VARIANT_BOOL isAsync )
2297 {
2298     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2299
2300     TRACE("(%p)->(%d)\n", This, isAsync);
2301     This->async = isAsync;
2302     return S_OK;
2303 }
2304
2305
2306 static HRESULT WINAPI domdoc_abort(
2307     IXMLDOMDocument3 *iface )
2308 {
2309     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2310     FIXME("%p\n", This);
2311     return E_NOTIMPL;
2312 }
2313
2314
2315 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2316 static HRESULT WINAPI domdoc_loadXML(
2317     IXMLDOMDocument3 *iface,
2318     BSTR bstrXML,
2319     VARIANT_BOOL* isSuccessful )
2320 {
2321     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2322     xmlDocPtr xmldoc = NULL;
2323     HRESULT hr = S_FALSE, hr2;
2324
2325     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2326
2327     assert ( &This->node );
2328
2329     if ( isSuccessful )
2330     {
2331         *isSuccessful = VARIANT_FALSE;
2332
2333         if ( bstrXML )
2334         {
2335             xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2336             if ( !xmldoc )
2337             {
2338                 This->error = E_FAIL;
2339                 TRACE("failed to parse document\n");
2340             }
2341             else
2342             {
2343                 hr = This->error = S_OK;
2344                 *isSuccessful = VARIANT_TRUE;
2345                 TRACE("parsed document %p\n", xmldoc);
2346             }
2347         }
2348     }
2349     if(!xmldoc)
2350         xmldoc = xmlNewDoc(NULL);
2351
2352     xmldoc->_private = create_priv();
2353
2354     hr2 = attach_xmldoc(This, xmldoc);
2355     if( FAILED(hr2) )
2356         hr = hr2;
2357
2358     return hr;
2359 }
2360
2361 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2362 {
2363     DWORD written = -1;
2364
2365     if(!WriteFile(ctx, buffer, len, &written, NULL))
2366     {
2367         WARN("write error\n");
2368         return -1;
2369     }
2370     else
2371         return written;
2372 }
2373
2374 static int XMLCALL domdoc_save_closecallback(void *ctx)
2375 {
2376     return CloseHandle(ctx) ? 0 : -1;
2377 }
2378
2379 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2380 {
2381     ULONG written = 0;
2382     HRESULT hr;
2383
2384     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2385     if (hr != S_OK)
2386     {
2387         WARN("stream write error: 0x%08x\n", hr);
2388         return -1;
2389     }
2390     else
2391         return written;
2392 }
2393
2394 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2395 {
2396     IStream_Release((IStream*)ctx);
2397     return 0;
2398 }
2399
2400 static HRESULT WINAPI domdoc_save(
2401     IXMLDOMDocument3 *iface,
2402     VARIANT destination )
2403 {
2404     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2405     xmlSaveCtxtPtr ctx = NULL;
2406     xmlNodePtr xmldecl;
2407     HRESULT ret = S_OK;
2408
2409     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2410
2411     switch (V_VT(&destination))
2412     {
2413     case VT_UNKNOWN:
2414         {
2415             IUnknown *pUnk = V_UNKNOWN(&destination);
2416             IXMLDOMDocument2 *document;
2417             IStream *stream;
2418
2419             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2420             if(ret == S_OK)
2421             {
2422                 VARIANT_BOOL success;
2423                 BSTR xml;
2424
2425                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2426                 if(ret == S_OK)
2427                 {
2428                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2429                     SysFreeString(xml);
2430                 }
2431
2432                 IXMLDOMDocument3_Release(document);
2433                 return ret;
2434             }
2435
2436             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2437             if(ret == S_OK)
2438             {
2439                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2440                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2441
2442                 if(!ctx)
2443                 {
2444                     IStream_Release(stream);
2445                     return E_FAIL;
2446                 }
2447             }
2448         }
2449         break;
2450
2451     case VT_BSTR:
2452     case VT_BSTR | VT_BYREF:
2453         {
2454             /* save with file path */
2455             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2456                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2457             if( handle == INVALID_HANDLE_VALUE )
2458             {
2459                 WARN("failed to create file\n");
2460                 return E_FAIL;
2461             }
2462
2463             /* disable top XML declaration */
2464             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2465                               handle, NULL, XML_SAVE_NO_DECL);
2466             if (!ctx)
2467             {
2468                 CloseHandle(handle);
2469                 return E_FAIL;
2470             }
2471         }
2472         break;
2473
2474     default:
2475         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2476         return S_FALSE;
2477     }
2478
2479     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2480     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2481     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2482
2483     /* will release resources through close callback */
2484     xmlSaveClose(ctx);
2485
2486     return ret;
2487 }
2488
2489 static HRESULT WINAPI domdoc_get_validateOnParse(
2490     IXMLDOMDocument3 *iface,
2491     VARIANT_BOOL* isValidating )
2492 {
2493     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2494     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2495     *isValidating = This->validating;
2496     return S_OK;
2497 }
2498
2499
2500 static HRESULT WINAPI domdoc_put_validateOnParse(
2501     IXMLDOMDocument3 *iface,
2502     VARIANT_BOOL isValidating )
2503 {
2504     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505     TRACE("(%p)->(%d)\n", This, isValidating);
2506     This->validating = isValidating;
2507     return S_OK;
2508 }
2509
2510
2511 static HRESULT WINAPI domdoc_get_resolveExternals(
2512     IXMLDOMDocument3 *iface,
2513     VARIANT_BOOL* isResolving )
2514 {
2515     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2516     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2517     *isResolving = This->resolving;
2518     return S_OK;
2519 }
2520
2521
2522 static HRESULT WINAPI domdoc_put_resolveExternals(
2523     IXMLDOMDocument3 *iface,
2524     VARIANT_BOOL isResolving )
2525 {
2526     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2527     TRACE("(%p)->(%d)\n", This, isResolving);
2528     This->resolving = isResolving;
2529     return S_OK;
2530 }
2531
2532
2533 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2534     IXMLDOMDocument3 *iface,
2535     VARIANT_BOOL* isPreserving )
2536 {
2537     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2538     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2539     *isPreserving = This->properties->preserving;
2540     return S_OK;
2541 }
2542
2543
2544 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2545     IXMLDOMDocument3 *iface,
2546     VARIANT_BOOL isPreserving )
2547 {
2548     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2549     TRACE("(%p)->(%d)\n", This, isPreserving);
2550     This->properties->preserving = isPreserving;
2551     return S_OK;
2552 }
2553
2554
2555 static HRESULT WINAPI domdoc_put_onreadystatechange(
2556     IXMLDOMDocument3 *iface,
2557     VARIANT event )
2558 {
2559     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2560
2561     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2562     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2563 }
2564
2565
2566 static HRESULT WINAPI domdoc_put_onDataAvailable(
2567     IXMLDOMDocument3 *iface,
2568     VARIANT onDataAvailableSink )
2569 {
2570     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2571     FIXME("%p\n", This);
2572     return E_NOTIMPL;
2573 }
2574
2575 static HRESULT WINAPI domdoc_put_onTransformNode(
2576     IXMLDOMDocument3 *iface,
2577     VARIANT onTransformNodeSink )
2578 {
2579     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2580     FIXME("%p\n", This);
2581     return E_NOTIMPL;
2582 }
2583
2584 static HRESULT WINAPI domdoc_get_namespaces(
2585     IXMLDOMDocument3* iface,
2586     IXMLDOMSchemaCollection** schemaCollection )
2587 {
2588     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2589     FIXME("(%p)->(%p)\n", This, schemaCollection);
2590     return E_NOTIMPL;
2591 }
2592
2593 static HRESULT WINAPI domdoc_get_schemas(
2594     IXMLDOMDocument3* iface,
2595     VARIANT* var1 )
2596 {
2597     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2598     HRESULT hr = S_FALSE;
2599     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2600
2601     TRACE("(%p)->(%p)\n", This, var1);
2602
2603     VariantInit(var1); /* Test shows we don't call VariantClear here */
2604     V_VT(var1) = VT_NULL;
2605
2606     if(cur_schema)
2607     {
2608         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2609         if(SUCCEEDED(hr))
2610             V_VT(var1) = VT_DISPATCH;
2611     }
2612     return hr;
2613 }
2614
2615 static HRESULT WINAPI domdoc_putref_schemas(
2616     IXMLDOMDocument3* iface,
2617     VARIANT var1)
2618 {
2619     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2620     HRESULT hr = E_FAIL;
2621     IXMLDOMSchemaCollection2* new_schema = NULL;
2622
2623     FIXME("(%p): semi-stub\n", This);
2624     switch(V_VT(&var1))
2625     {
2626     case VT_UNKNOWN:
2627         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2628         break;
2629
2630     case VT_DISPATCH:
2631         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2632         break;
2633
2634     case VT_NULL:
2635     case VT_EMPTY:
2636         hr = S_OK;
2637         break;
2638
2639     default:
2640         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2641     }
2642
2643     if(SUCCEEDED(hr))
2644     {
2645         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2646         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2647     }
2648
2649     return hr;
2650 }
2651
2652 static inline BOOL is_wellformed(xmlDocPtr doc)
2653 {
2654 #ifdef HAVE_XMLDOC_PROPERTIES
2655     return doc->properties & XML_DOC_WELLFORMED;
2656 #else
2657     /* Not a full check, but catches the worst violations */
2658     xmlNodePtr child;
2659     int root = 0;
2660
2661     for (child = doc->children; child != NULL; child = child->next)
2662     {
2663         switch (child->type)
2664         {
2665         case XML_ELEMENT_NODE:
2666             if (++root > 1)
2667                 return FALSE;
2668             break;
2669         case XML_TEXT_NODE:
2670         case XML_CDATA_SECTION_NODE:
2671             return FALSE;
2672             break;
2673         default:
2674             break;
2675         }
2676     }
2677
2678     return root == 1;
2679 #endif
2680 }
2681
2682 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2683 {
2684     va_list ap;
2685     va_start(ap, msg);
2686     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2687     va_end(ap);
2688 }
2689
2690 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2691 {
2692     va_list ap;
2693     va_start(ap, msg);
2694     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2695     va_end(ap);
2696 }
2697
2698 static HRESULT WINAPI domdoc_validateNode(
2699     IXMLDOMDocument3* iface,
2700     IXMLDOMNode* node,
2701     IXMLDOMParseError** err)
2702 {
2703     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2704     LONG state, err_code = 0;
2705     HRESULT hr = S_OK;
2706     int validated = 0;
2707
2708     TRACE("(%p)->(%p, %p)\n", This, node, err);
2709     domdoc_get_readyState(iface, &state);
2710     if (state != READYSTATE_COMPLETE)
2711     {
2712         if (err)
2713            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2714         return E_PENDING;
2715     }
2716
2717     if (!node)
2718     {
2719         if (err)
2720             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2721         return E_POINTER;
2722     }
2723
2724     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2725     {
2726         if (err)
2727             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2728         return E_FAIL;
2729     }
2730
2731     if (!is_wellformed(get_doc(This)))
2732     {
2733         ERR("doc not well-formed\n");
2734         if (err)
2735             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2736         return S_FALSE;
2737     }
2738
2739     /* DTD validation */
2740     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2741     {
2742         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2743         vctx->error = validate_error;
2744         vctx->warning = validate_warning;
2745         ++validated;
2746
2747         if (!((node == (IXMLDOMNode*)iface)?
2748               xmlValidateDocument(vctx, get_doc(This)) :
2749               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2750         {
2751             /* TODO: get a real error code here */
2752             TRACE("DTD validation failed\n");
2753             err_code = E_XML_INVALID;
2754             hr = S_FALSE;
2755         }
2756         xmlFreeValidCtxt(vctx);
2757     }
2758
2759     /* Schema validation */
2760     if (hr == S_OK && This->properties->schemaCache != NULL)
2761     {
2762
2763         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2764         if (SUCCEEDED(hr))
2765         {
2766             ++validated;
2767             /* TODO: get a real error code here */
2768             if (hr == S_OK)
2769             {
2770                 TRACE("schema validation succeeded\n");
2771             }
2772             else
2773             {
2774                 ERR("schema validation failed\n");
2775                 err_code = E_XML_INVALID;
2776             }
2777         }
2778         else
2779         {
2780             /* not really OK, just didn't find a schema for the ns */
2781             hr = S_OK;
2782         }
2783     }
2784
2785     if (!validated)
2786     {
2787         ERR("no DTD or schema found\n");
2788         err_code = E_XML_NODTD;
2789         hr = S_FALSE;
2790     }
2791
2792     if (err)
2793         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2794
2795     return hr;
2796 }
2797
2798 static HRESULT WINAPI domdoc_validate(
2799     IXMLDOMDocument3* iface,
2800     IXMLDOMParseError** err)
2801 {
2802     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2803     TRACE("(%p)->(%p)\n", This, err);
2804     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2805 }
2806
2807 static HRESULT WINAPI domdoc_setProperty(
2808     IXMLDOMDocument3* iface,
2809     BSTR p,
2810     VARIANT var)
2811 {
2812     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2813
2814     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2815
2816     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2817     {
2818         VARIANT varStr;
2819         HRESULT hr;
2820         BSTR bstr;
2821
2822         V_VT(&varStr) = VT_EMPTY;
2823         if (V_VT(&var) != VT_BSTR)
2824         {
2825             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2826                 return hr;
2827             bstr = V_BSTR(&varStr);
2828         }
2829         else
2830             bstr = V_BSTR(&var);
2831
2832         hr = S_OK;
2833         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2834             This->properties->XPath = TRUE;
2835         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2836             This->properties->XPath = FALSE;
2837         else
2838             hr = E_FAIL;
2839
2840         VariantClear(&varStr);
2841         return hr;
2842     }
2843     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2844     {
2845         VARIANT varStr;
2846         HRESULT hr;
2847         BSTR bstr;
2848         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2849         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2850         xmlXPathContextPtr ctx;
2851         struct list *pNsList;
2852         select_ns_entry* pNsEntry = NULL;
2853
2854         V_VT(&varStr) = VT_EMPTY;
2855         if (V_VT(&var) != VT_BSTR)
2856         {
2857             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2858                 return hr;
2859             bstr = V_BSTR(&varStr);
2860         }
2861         else
2862             bstr = V_BSTR(&var);
2863
2864         hr = S_OK;
2865
2866         pNsList = &(This->properties->selectNsList);
2867         clear_selectNsList(pNsList);
2868         heap_free(nsStr);
2869         nsStr = xmlchar_from_wchar(bstr);
2870
2871         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2872
2873         This->properties->selectNsStr = nsStr;
2874         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2875         if (bstr && *bstr)
2876         {
2877             ctx = xmlXPathNewContext(This->node.node->doc);
2878             pTokBegin = nsStr;
2879             for (; *pTokBegin; pTokBegin = pTokEnd)
2880             {
2881                 if (pNsEntry != NULL)
2882                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2883                 else
2884                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2885
2886                 while (*pTokBegin == ' ')
2887                     ++pTokBegin;
2888                 pTokEnd = pTokBegin;
2889                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2890                     ++pTokEnd;
2891
2892                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2893                 {
2894                     hr = E_FAIL;
2895                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2896                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2897                     continue;
2898                 }
2899
2900                 pTokBegin += 5;
2901                 if (*pTokBegin == '=')
2902                 {
2903                     /*valid for XSLPattern?*/
2904                     FIXME("Setting default xmlns not supported - skipping.\n");
2905                     continue;
2906                 }
2907                 else if (*pTokBegin == ':')
2908                 {
2909                     pNsEntry->prefix = ++pTokBegin;
2910                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2911                         ;
2912
2913                     if (pTokInner == pTokEnd)
2914                     {
2915                         hr = E_FAIL;
2916                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2917                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2918                         continue;
2919                     }
2920
2921                     pNsEntry->prefix_end = *pTokInner;
2922                     *pTokInner = 0;
2923                     ++pTokInner;
2924
2925                     if (pTokEnd-pTokInner > 1 &&
2926                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2927                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2928                     {
2929                         pNsEntry->href = ++pTokInner;
2930                         pNsEntry->href_end = *(pTokEnd-1);
2931                         *(pTokEnd-1) = 0;
2932                         list_add_tail(pNsList, &pNsEntry->entry);
2933                         /*let libxml figure out if they're valid from here ;)*/
2934                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2935                         {
2936                             hr = E_FAIL;
2937                         }
2938                         pNsEntry = NULL;
2939                         continue;
2940                     }
2941                     else
2942                     {
2943                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2944                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2945                         list_add_tail(pNsList, &pNsEntry->entry);
2946
2947                         pNsEntry = NULL;
2948                         hr = E_FAIL;
2949                         continue;
2950                     }
2951                 }
2952                 else
2953                 {
2954                     hr = E_FAIL;
2955                     continue;
2956                 }
2957             }
2958             heap_free(pNsEntry);
2959             xmlXPathFreeContext(ctx);
2960         }
2961
2962         VariantClear(&varStr);
2963         return hr;
2964     }
2965     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2966              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2967              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2968     {
2969         /* Ignore */
2970         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2971         return S_OK;
2972     }
2973
2974     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2975     return E_FAIL;
2976 }
2977
2978 static HRESULT WINAPI domdoc_getProperty(
2979     IXMLDOMDocument3* iface,
2980     BSTR p,
2981     VARIANT* var)
2982 {
2983     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2984
2985     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2986
2987     if (!var)
2988         return E_INVALIDARG;
2989
2990     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2991     {
2992         V_VT(var) = VT_BSTR;
2993         V_BSTR(var) = This->properties->XPath ?
2994                       SysAllocString(PropValueXPathW) :
2995                       SysAllocString(PropValueXSLPatternW);
2996         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2997     }
2998     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2999     {
3000         int lenA, lenW;
3001         BSTR rebuiltStr, cur;
3002         const xmlChar *nsStr;
3003         struct list *pNsList;
3004         select_ns_entry* pNsEntry;
3005
3006         V_VT(var) = VT_BSTR;
3007         nsStr = This->properties->selectNsStr;
3008         pNsList = &This->properties->selectNsList;
3009         lenA = This->properties->selectNsStr_len;
3010         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3011         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3012         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3013         cur = rebuiltStr;
3014         /* this is fine because all of the chars that end tokens are ASCII*/
3015         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3016         {
3017             while (*cur != 0) ++cur;
3018             if (pNsEntry->prefix_end)
3019             {
3020                 *cur = pNsEntry->prefix_end;
3021                 while (*cur != 0) ++cur;
3022             }
3023
3024             if (pNsEntry->href_end)
3025             {
3026                 *cur = pNsEntry->href_end;
3027             }
3028         }
3029         V_BSTR(var) = SysAllocString(rebuiltStr);
3030         heap_free(rebuiltStr);
3031         return S_OK;
3032     }
3033
3034     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3035     return E_FAIL;
3036 }
3037
3038 static HRESULT WINAPI domdoc_importNode(
3039     IXMLDOMDocument3* iface,
3040     IXMLDOMNode* node,
3041     VARIANT_BOOL deep,
3042     IXMLDOMNode** clone)
3043 {
3044     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3045     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3046     return E_NOTIMPL;
3047 }
3048
3049 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3050 {
3051     domdoc_QueryInterface,
3052     domdoc_AddRef,
3053     domdoc_Release,
3054     domdoc_GetTypeInfoCount,
3055     domdoc_GetTypeInfo,
3056     domdoc_GetIDsOfNames,
3057     domdoc_Invoke,
3058     domdoc_get_nodeName,
3059     domdoc_get_nodeValue,
3060     domdoc_put_nodeValue,
3061     domdoc_get_nodeType,
3062     domdoc_get_parentNode,
3063     domdoc_get_childNodes,
3064     domdoc_get_firstChild,
3065     domdoc_get_lastChild,
3066     domdoc_get_previousSibling,
3067     domdoc_get_nextSibling,
3068     domdoc_get_attributes,
3069     domdoc_insertBefore,
3070     domdoc_replaceChild,
3071     domdoc_removeChild,
3072     domdoc_appendChild,
3073     domdoc_hasChildNodes,
3074     domdoc_get_ownerDocument,
3075     domdoc_cloneNode,
3076     domdoc_get_nodeTypeString,
3077     domdoc_get_text,
3078     domdoc_put_text,
3079     domdoc_get_specified,
3080     domdoc_get_definition,
3081     domdoc_get_nodeTypedValue,
3082     domdoc_put_nodeTypedValue,
3083     domdoc_get_dataType,
3084     domdoc_put_dataType,
3085     domdoc_get_xml,
3086     domdoc_transformNode,
3087     domdoc_selectNodes,
3088     domdoc_selectSingleNode,
3089     domdoc_get_parsed,
3090     domdoc_get_namespaceURI,
3091     domdoc_get_prefix,
3092     domdoc_get_baseName,
3093     domdoc_transformNodeToObject,
3094     domdoc_get_doctype,
3095     domdoc_get_implementation,
3096     domdoc_get_documentElement,
3097     domdoc_put_documentElement,
3098     domdoc_createElement,
3099     domdoc_createDocumentFragment,
3100     domdoc_createTextNode,
3101     domdoc_createComment,
3102     domdoc_createCDATASection,
3103     domdoc_createProcessingInstruction,
3104     domdoc_createAttribute,
3105     domdoc_createEntityReference,
3106     domdoc_getElementsByTagName,
3107     domdoc_createNode,
3108     domdoc_nodeFromID,
3109     domdoc_load,
3110     domdoc_get_readyState,
3111     domdoc_get_parseError,
3112     domdoc_get_url,
3113     domdoc_get_async,
3114     domdoc_put_async,
3115     domdoc_abort,
3116     domdoc_loadXML,
3117     domdoc_save,
3118     domdoc_get_validateOnParse,
3119     domdoc_put_validateOnParse,
3120     domdoc_get_resolveExternals,
3121     domdoc_put_resolveExternals,
3122     domdoc_get_preserveWhiteSpace,
3123     domdoc_put_preserveWhiteSpace,
3124     domdoc_put_onreadystatechange,
3125     domdoc_put_onDataAvailable,
3126     domdoc_put_onTransformNode,
3127     domdoc_get_namespaces,
3128     domdoc_get_schemas,
3129     domdoc_putref_schemas,
3130     domdoc_validate,
3131     domdoc_setProperty,
3132     domdoc_getProperty,
3133     domdoc_validateNode,
3134     domdoc_importNode
3135 };
3136
3137 /* IConnectionPointContainer */
3138 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3139                                                               REFIID riid, void **ppv)
3140 {
3141     domdoc *This = impl_from_IConnectionPointContainer(iface);
3142     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3143 }
3144
3145 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3146 {
3147     domdoc *This = impl_from_IConnectionPointContainer(iface);
3148     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3149 }
3150
3151 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3152 {
3153     domdoc *This = impl_from_IConnectionPointContainer(iface);
3154     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3155 }
3156
3157 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3158         IEnumConnectionPoints **ppEnum)
3159 {
3160     domdoc *This = impl_from_IConnectionPointContainer(iface);
3161     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3162     return E_NOTIMPL;
3163 }
3164
3165 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3166         REFIID riid, IConnectionPoint **cp)
3167 {
3168     domdoc *This = impl_from_IConnectionPointContainer(iface);
3169     ConnectionPoint *iter;
3170
3171     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3172
3173     *cp = NULL;
3174
3175     for(iter = This->cp_list; iter; iter = iter->next)
3176     {
3177         if (IsEqualGUID(iter->iid, riid))
3178             *cp = &iter->IConnectionPoint_iface;
3179     }
3180
3181     if (*cp)
3182     {
3183         IConnectionPoint_AddRef(*cp);
3184         return S_OK;
3185     }
3186
3187     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3188     return CONNECT_E_NOCONNECTION;
3189
3190 }
3191
3192 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3193 {
3194     ConnectionPointContainer_QueryInterface,
3195     ConnectionPointContainer_AddRef,
3196     ConnectionPointContainer_Release,
3197     ConnectionPointContainer_EnumConnectionPoints,
3198     ConnectionPointContainer_FindConnectionPoint
3199 };
3200
3201 /* IConnectionPoint */
3202 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3203                                                      REFIID riid, void **ppv)
3204 {
3205     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3206
3207     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3208
3209     *ppv = NULL;
3210
3211     if (IsEqualGUID(&IID_IUnknown, riid) ||
3212         IsEqualGUID(&IID_IConnectionPoint, riid))
3213     {
3214         *ppv = iface;
3215     }
3216
3217     if (*ppv)
3218     {
3219         IConnectionPoint_AddRef(iface);
3220         return S_OK;
3221     }
3222
3223     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3224     return E_NOINTERFACE;
3225 }
3226
3227 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3228 {
3229     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3230     return IConnectionPointContainer_AddRef(This->container);
3231 }
3232
3233 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3234 {
3235     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3236     return IConnectionPointContainer_Release(This->container);
3237 }
3238
3239 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3240 {
3241     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3242
3243     TRACE("(%p)->(%p)\n", This, iid);
3244
3245     if (!iid) return E_POINTER;
3246
3247     *iid = *This->iid;
3248     return S_OK;
3249 }
3250
3251 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3252         IConnectionPointContainer **container)
3253 {
3254     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3255
3256     TRACE("(%p)->(%p)\n", This, container);
3257
3258     if (!container) return E_POINTER;
3259
3260     *container = This->container;
3261     IConnectionPointContainer_AddRef(*container);
3262     return S_OK;
3263 }
3264
3265 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3266                                              DWORD *pdwCookie)
3267 {
3268     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3269     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3270     return E_NOTIMPL;
3271 }
3272
3273 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3274 {
3275     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3276
3277     TRACE("(%p)->(%d)\n", This, cookie);
3278
3279     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3280         return CONNECT_E_NOCONNECTION;
3281
3282     IUnknown_Release(This->sinks[cookie-1].unk);
3283     This->sinks[cookie-1].unk = NULL;
3284
3285     return S_OK;
3286 }
3287
3288 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3289                                                       IEnumConnections **ppEnum)
3290 {
3291     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3292     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3293     return E_NOTIMPL;
3294 }
3295
3296 static const IConnectionPointVtbl ConnectionPointVtbl =
3297 {
3298     ConnectionPoint_QueryInterface,
3299     ConnectionPoint_AddRef,
3300     ConnectionPoint_Release,
3301     ConnectionPoint_GetConnectionInterface,
3302     ConnectionPoint_GetConnectionPointContainer,
3303     ConnectionPoint_Advise,
3304     ConnectionPoint_Unadvise,
3305     ConnectionPoint_EnumConnections
3306 };
3307
3308 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3309 {
3310     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3311     cp->doc = doc;
3312     cp->iid = riid;
3313     cp->sinks = NULL;
3314     cp->sinks_size = 0;
3315
3316     cp->next = doc->cp_list;
3317     doc->cp_list = cp;
3318
3319     cp->container = &doc->IConnectionPointContainer_iface;
3320 }
3321
3322 /* domdoc implementation of IObjectWithSite */
3323 static HRESULT WINAPI
3324 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3325 {
3326     domdoc *This = impl_from_IObjectWithSite(iface);
3327     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3328 }
3329
3330 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3331 {
3332     domdoc *This = impl_from_IObjectWithSite(iface);
3333     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3334 }
3335
3336 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3337 {
3338     domdoc *This = impl_from_IObjectWithSite(iface);
3339     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3340 }
3341
3342 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3343 {
3344     domdoc *This = impl_from_IObjectWithSite(iface);
3345
3346     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3347
3348     if ( !This->site )
3349         return E_FAIL;
3350
3351     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3352 }
3353
3354 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3355 {
3356     domdoc *This = impl_from_IObjectWithSite(iface);
3357
3358     TRACE("(%p)->(%p)\n", iface, punk);
3359
3360     if(!punk)
3361     {
3362         if(This->site)
3363         {
3364             IUnknown_Release( This->site );
3365             This->site = NULL;
3366         }
3367
3368         return S_OK;
3369     }
3370
3371     IUnknown_AddRef( punk );
3372
3373     if(This->site)
3374         IUnknown_Release( This->site );
3375
3376     This->site = punk;
3377
3378     return S_OK;
3379 }
3380
3381 static const IObjectWithSiteVtbl domdocObjectSite =
3382 {
3383     domdoc_ObjectWithSite_QueryInterface,
3384     domdoc_ObjectWithSite_AddRef,
3385     domdoc_ObjectWithSite_Release,
3386     domdoc_ObjectWithSite_SetSite,
3387     domdoc_ObjectWithSite_GetSite
3388 };
3389
3390 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3391 {
3392     domdoc *This = impl_from_IObjectSafety(iface);
3393     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3394 }
3395
3396 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3397 {
3398     domdoc *This = impl_from_IObjectSafety(iface);
3399     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3400 }
3401
3402 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3403 {
3404     domdoc *This = impl_from_IObjectSafety(iface);
3405     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3406 }
3407
3408 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3409
3410 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3411         DWORD *supported, DWORD *enabled)
3412 {
3413     domdoc *This = impl_from_IObjectSafety(iface);
3414
3415     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3416
3417     if(!supported || !enabled) return E_POINTER;
3418
3419     *supported = SAFETY_SUPPORTED_OPTIONS;
3420     *enabled = This->safeopt;
3421
3422     return S_OK;
3423 }
3424
3425 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3426         DWORD mask, DWORD enabled)
3427 {
3428     domdoc *This = impl_from_IObjectSafety(iface);
3429     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3430
3431     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3432         return E_FAIL;
3433
3434     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3435
3436     return S_OK;
3437 }
3438
3439 #undef SAFETY_SUPPORTED_OPTIONS
3440
3441 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3442     domdoc_Safety_QueryInterface,
3443     domdoc_Safety_AddRef,
3444     domdoc_Safety_Release,
3445     domdoc_Safety_GetInterfaceSafetyOptions,
3446     domdoc_Safety_SetInterfaceSafetyOptions
3447 };
3448
3449 static const tid_t domdoc_iface_tids[] = {
3450     IXMLDOMNode_tid,
3451     IXMLDOMDocument_tid,
3452     IXMLDOMDocument2_tid,
3453     0
3454 };
3455 static dispex_static_data_t domdoc_dispex = {
3456     NULL,
3457     IXMLDOMDocument2_tid,
3458     NULL,
3459     domdoc_iface_tids
3460 };
3461
3462 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3463 {
3464     domdoc *doc;
3465
3466     doc = heap_alloc( sizeof (*doc) );
3467     if( !doc )
3468         return E_OUTOFMEMORY;
3469
3470     doc->IXMLDOMDocument3_iface.lpVtbl = &domdoc_vtbl;
3471     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3472     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3473     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3474     doc->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
3475     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3476     doc->ref = 1;
3477     doc->async = VARIANT_TRUE;
3478     doc->validating = 0;
3479     doc->resolving = 0;
3480     doc->properties = properties_from_xmlDocPtr(xmldoc);
3481     doc->error = S_OK;
3482     doc->stream = NULL;
3483     doc->site = NULL;
3484     doc->safeopt = 0;
3485     doc->bsc = NULL;
3486     doc->cp_list = NULL;
3487     memset(doc->events, 0, sizeof(doc->events));
3488
3489     /* events connection points */
3490     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3491     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3492     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3493
3494     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3495             &domdoc_dispex);
3496
3497     *document = &doc->IXMLDOMDocument3_iface;
3498
3499     TRACE("returning iface %p\n", *document);
3500     return S_OK;
3501 }
3502
3503 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3504 {
3505     xmlDocPtr xmldoc;
3506     HRESULT hr;
3507
3508     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3509
3510     xmldoc = xmlNewDoc(NULL);
3511     if(!xmldoc)
3512         return E_OUTOFMEMORY;
3513
3514     xmldoc->_private = create_priv();
3515     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3516
3517     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3518     if(FAILED(hr))
3519     {
3520         free_properties(properties_from_xmlDocPtr(xmldoc));
3521         heap_free(xmldoc->_private);
3522         xmlFreeDoc(xmldoc);
3523         return hr;
3524     }
3525
3526     return hr;
3527 }
3528
3529 IUnknown* create_domdoc( xmlNodePtr document )
3530 {
3531     void* pObj = NULL;
3532     HRESULT hr;
3533
3534     TRACE("(%p)\n", document);
3535
3536     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3537     if (FAILED(hr))
3538         return NULL;
3539
3540     return pObj;
3541 }
3542
3543 #else
3544
3545 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3546 {
3547     MESSAGE("This program tried to use a DOMDocument object, but\n"
3548             "libxml2 support was not present at compile time.\n");
3549     return E_NOTIMPL;
3550 }
3551
3552 #endif