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