msxml3: Downgrade FIXME to TRACE for unsupported interfaces.
[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 xmlSource,
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)->type %d\n", This, V_VT(&xmlSource) );
2118
2119     *isSuccessful = VARIANT_FALSE;
2120
2121     assert( &This->node );
2122
2123     switch( V_VT(&xmlSource) )
2124     {
2125     case VT_BSTR:
2126         filename = V_BSTR(&xmlSource);
2127         break;
2128     case VT_UNKNOWN:
2129         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2130         if(hr == S_OK)
2131         {
2132             if(pNewDoc)
2133             {
2134                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2135                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2136                 hr = attach_xmldoc(This, xmldoc);
2137
2138                 if(SUCCEEDED(hr))
2139                     *isSuccessful = VARIANT_TRUE;
2140
2141                 return hr;
2142             }
2143         }
2144         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2145         if(hr == S_OK)
2146         {
2147             IPersistStream *pDocStream;
2148             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2149             if(hr == S_OK)
2150             {
2151                 hr = IPersistStream_Load(pDocStream, pStream);
2152                 IStream_Release(pStream);
2153                 if(hr == S_OK)
2154                 {
2155                     *isSuccessful = VARIANT_TRUE;
2156
2157                     TRACE("Using IStream to load Document\n");
2158                     return S_OK;
2159                 }
2160                 else
2161                 {
2162                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2163                 }
2164             }
2165             else
2166             {
2167                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2168             }
2169         }
2170         else
2171         {
2172             /* ISequentialStream */
2173             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2174         }
2175         break;
2176      default:
2177             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2178      }
2179
2180     TRACE("filename (%s)\n", debugstr_w(filename));
2181
2182     if ( filename )
2183     {
2184         hr = doread( This, filename );
2185
2186         if ( FAILED(hr) )
2187             This->error = E_FAIL;
2188         else
2189         {
2190             hr = This->error = S_OK;
2191             *isSuccessful = VARIANT_TRUE;
2192         }
2193     }
2194
2195     if(!filename || FAILED(hr)) {
2196         xmldoc = xmlNewDoc(NULL);
2197         xmldoc->_private = create_priv();
2198         hr = attach_xmldoc(This, xmldoc);
2199         if(SUCCEEDED(hr))
2200             hr = S_FALSE;
2201     }
2202
2203     TRACE("ret (%d)\n", hr);
2204
2205     return hr;
2206 }
2207
2208
2209 static HRESULT WINAPI domdoc_get_readyState(
2210     IXMLDOMDocument3 *iface,
2211     LONG *value )
2212 {
2213     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2214     FIXME("stub! (%p)->(%p)\n", This, value);
2215
2216     if (!value)
2217         return E_INVALIDARG;
2218
2219     *value = READYSTATE_COMPLETE;
2220     return S_OK;
2221 }
2222
2223
2224 static HRESULT WINAPI domdoc_get_parseError(
2225     IXMLDOMDocument3 *iface,
2226     IXMLDOMParseError** errorObj )
2227 {
2228     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2229     static const WCHAR err[] = {'e','r','r','o','r',0};
2230     BSTR error_string = NULL;
2231
2232     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2233
2234     if(This->error)
2235         error_string = SysAllocString(err);
2236
2237     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2238     if(!*errorObj) return E_OUTOFMEMORY;
2239     return S_OK;
2240 }
2241
2242
2243 static HRESULT WINAPI domdoc_get_url(
2244     IXMLDOMDocument3 *iface,
2245     BSTR* urlString )
2246 {
2247     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2248     FIXME("(%p)->(%p)\n", This, urlString);
2249     return E_NOTIMPL;
2250 }
2251
2252
2253 static HRESULT WINAPI domdoc_get_async(
2254     IXMLDOMDocument3 *iface,
2255     VARIANT_BOOL* isAsync )
2256 {
2257     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2258
2259     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2260     *isAsync = This->async;
2261     return S_OK;
2262 }
2263
2264
2265 static HRESULT WINAPI domdoc_put_async(
2266     IXMLDOMDocument3 *iface,
2267     VARIANT_BOOL isAsync )
2268 {
2269     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2270
2271     TRACE("(%p)->(%d)\n", This, isAsync);
2272     This->async = isAsync;
2273     return S_OK;
2274 }
2275
2276
2277 static HRESULT WINAPI domdoc_abort(
2278     IXMLDOMDocument3 *iface )
2279 {
2280     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2281     FIXME("%p\n", This);
2282     return E_NOTIMPL;
2283 }
2284
2285
2286 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2287 {
2288     UINT len;
2289     LPSTR str;
2290
2291     len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2292     str = heap_alloc( len );
2293     if ( !str )
2294         return FALSE;
2295     WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2296     *plen = len;
2297     *pstr = str;
2298     return TRUE;
2299 }
2300
2301 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2302 static HRESULT WINAPI domdoc_loadXML(
2303     IXMLDOMDocument3 *iface,
2304     BSTR bstrXML,
2305     VARIANT_BOOL* isSuccessful )
2306 {
2307     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2308     static const xmlChar encoding[] = "UTF-8";
2309     xmlDocPtr xmldoc = NULL;
2310     HRESULT hr = S_FALSE, hr2;
2311     char *str;
2312     int len;
2313
2314     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2315
2316     assert ( &This->node );
2317
2318     if ( isSuccessful )
2319     {
2320         *isSuccessful = VARIANT_FALSE;
2321
2322         if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2323         {
2324             xmldoc = doparse(This, str, len, encoding);
2325             heap_free( str );
2326             if ( !xmldoc )
2327             {
2328                 This->error = E_FAIL;
2329                 TRACE("failed to parse document\n");
2330             }
2331             else
2332             {
2333                 hr = This->error = S_OK;
2334                 *isSuccessful = VARIANT_TRUE;
2335                 TRACE("parsed document %p\n", xmldoc);
2336             }
2337         }
2338     }
2339     if(!xmldoc)
2340         xmldoc = xmlNewDoc(NULL);
2341
2342     xmldoc->_private = create_priv();
2343
2344     hr2 = attach_xmldoc(This, xmldoc);
2345     if( FAILED(hr2) )
2346         hr = hr2;
2347
2348     return hr;
2349 }
2350
2351 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2352 {
2353     DWORD written = -1;
2354
2355     if(!WriteFile(ctx, buffer, len, &written, NULL))
2356     {
2357         WARN("write error\n");
2358         return -1;
2359     }
2360     else
2361         return written;
2362 }
2363
2364 static int XMLCALL domdoc_save_closecallback(void *ctx)
2365 {
2366     return CloseHandle(ctx) ? 0 : -1;
2367 }
2368
2369 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2370 {
2371     ULONG written = 0;
2372     HRESULT hr;
2373
2374     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2375     if (hr != S_OK)
2376     {
2377         WARN("stream write error: 0x%08x\n", hr);
2378         return -1;
2379     }
2380     else
2381         return written;
2382 }
2383
2384 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2385 {
2386     IStream_Release((IStream*)ctx);
2387     return 0;
2388 }
2389
2390 static HRESULT WINAPI domdoc_save(
2391     IXMLDOMDocument3 *iface,
2392     VARIANT destination )
2393 {
2394     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2395     xmlSaveCtxtPtr ctx = NULL;
2396     xmlNodePtr xmldecl;
2397     HRESULT ret = S_OK;
2398
2399     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2400           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2401
2402     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2403     {
2404         FIXME("Unhandled vt %d\n", V_VT(&destination));
2405         return S_FALSE;
2406     }
2407
2408     if(V_VT(&destination) == VT_UNKNOWN)
2409     {
2410         IUnknown *pUnk = V_UNKNOWN(&destination);
2411         IXMLDOMDocument2 *document;
2412         IStream *stream;
2413
2414         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2415         if(ret == S_OK)
2416         {
2417             VARIANT_BOOL success;
2418             BSTR xml;
2419
2420             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2421             if(ret == S_OK)
2422             {
2423                 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2424                 SysFreeString(xml);
2425             }
2426
2427             IXMLDOMDocument3_Release(document);
2428             return ret;
2429         }
2430
2431         ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2432         if(ret == S_OK)
2433         {
2434             ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2435                 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2436
2437             if(!ctx)
2438             {
2439                 IStream_Release(stream);
2440                 return E_FAIL;
2441             }
2442         }
2443     }
2444     else
2445     {
2446         /* save with file path */
2447         HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2448                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2449         if( handle == INVALID_HANDLE_VALUE )
2450         {
2451             WARN("failed to create file\n");
2452             return E_FAIL;
2453         }
2454
2455         /* disable top XML declaration */
2456         ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2457                           handle, NULL, XML_SAVE_NO_DECL);
2458         if (!ctx)
2459         {
2460             CloseHandle(handle);
2461             return E_FAIL;
2462         }
2463     }
2464
2465     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2466     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2467     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2468
2469     /* will release resources through close callback */
2470     xmlSaveClose(ctx);
2471
2472     return ret;
2473 }
2474
2475 static HRESULT WINAPI domdoc_get_validateOnParse(
2476     IXMLDOMDocument3 *iface,
2477     VARIANT_BOOL* isValidating )
2478 {
2479     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2480     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2481     *isValidating = This->validating;
2482     return S_OK;
2483 }
2484
2485
2486 static HRESULT WINAPI domdoc_put_validateOnParse(
2487     IXMLDOMDocument3 *iface,
2488     VARIANT_BOOL isValidating )
2489 {
2490     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2491     TRACE("(%p)->(%d)\n", This, isValidating);
2492     This->validating = isValidating;
2493     return S_OK;
2494 }
2495
2496
2497 static HRESULT WINAPI domdoc_get_resolveExternals(
2498     IXMLDOMDocument3 *iface,
2499     VARIANT_BOOL* isResolving )
2500 {
2501     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2502     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2503     *isResolving = This->resolving;
2504     return S_OK;
2505 }
2506
2507
2508 static HRESULT WINAPI domdoc_put_resolveExternals(
2509     IXMLDOMDocument3 *iface,
2510     VARIANT_BOOL isResolving )
2511 {
2512     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2513     TRACE("(%p)->(%d)\n", This, isResolving);
2514     This->resolving = isResolving;
2515     return S_OK;
2516 }
2517
2518
2519 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2520     IXMLDOMDocument3 *iface,
2521     VARIANT_BOOL* isPreserving )
2522 {
2523     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2524     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2525     *isPreserving = This->properties->preserving;
2526     return S_OK;
2527 }
2528
2529
2530 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2531     IXMLDOMDocument3 *iface,
2532     VARIANT_BOOL isPreserving )
2533 {
2534     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2535     TRACE("(%p)->(%d)\n", This, isPreserving);
2536     This->properties->preserving = isPreserving;
2537     return S_OK;
2538 }
2539
2540
2541 static HRESULT WINAPI domdoc_put_onreadystatechange(
2542     IXMLDOMDocument3 *iface,
2543     VARIANT event )
2544 {
2545     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2546
2547     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2548     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2549 }
2550
2551
2552 static HRESULT WINAPI domdoc_put_onDataAvailable(
2553     IXMLDOMDocument3 *iface,
2554     VARIANT onDataAvailableSink )
2555 {
2556     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2557     FIXME("%p\n", This);
2558     return E_NOTIMPL;
2559 }
2560
2561 static HRESULT WINAPI domdoc_put_onTransformNode(
2562     IXMLDOMDocument3 *iface,
2563     VARIANT onTransformNodeSink )
2564 {
2565     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2566     FIXME("%p\n", This);
2567     return E_NOTIMPL;
2568 }
2569
2570 static HRESULT WINAPI domdoc_get_namespaces(
2571     IXMLDOMDocument3* iface,
2572     IXMLDOMSchemaCollection** schemaCollection )
2573 {
2574     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2575     FIXME("(%p)->(%p)\n", This, schemaCollection);
2576     return E_NOTIMPL;
2577 }
2578
2579 static HRESULT WINAPI domdoc_get_schemas(
2580     IXMLDOMDocument3* iface,
2581     VARIANT* var1 )
2582 {
2583     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2584     HRESULT hr = S_FALSE;
2585     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2586
2587     TRACE("(%p)->(%p)\n", This, var1);
2588
2589     VariantInit(var1); /* Test shows we don't call VariantClear here */
2590     V_VT(var1) = VT_NULL;
2591
2592     if(cur_schema)
2593     {
2594         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2595         if(SUCCEEDED(hr))
2596             V_VT(var1) = VT_DISPATCH;
2597     }
2598     return hr;
2599 }
2600
2601 static HRESULT WINAPI domdoc_putref_schemas(
2602     IXMLDOMDocument3* iface,
2603     VARIANT var1)
2604 {
2605     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2606     HRESULT hr = E_FAIL;
2607     IXMLDOMSchemaCollection2* new_schema = NULL;
2608
2609     FIXME("(%p): semi-stub\n", This);
2610     switch(V_VT(&var1))
2611     {
2612     case VT_UNKNOWN:
2613         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2614         break;
2615
2616     case VT_DISPATCH:
2617         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2618         break;
2619
2620     case VT_NULL:
2621     case VT_EMPTY:
2622         hr = S_OK;
2623         break;
2624
2625     default:
2626         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2627     }
2628
2629     if(SUCCEEDED(hr))
2630     {
2631         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2632         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2633     }
2634
2635     return hr;
2636 }
2637
2638 static inline BOOL is_wellformed(xmlDocPtr doc)
2639 {
2640 #ifdef HAVE_XMLDOC_PROPERTIES
2641     return doc->properties & XML_DOC_WELLFORMED;
2642 #else
2643     /* Not a full check, but catches the worst violations */
2644     xmlNodePtr child;
2645     int root = 0;
2646
2647     for (child = doc->children; child != NULL; child = child->next)
2648     {
2649         switch (child->type)
2650         {
2651         case XML_ELEMENT_NODE:
2652             if (++root > 1)
2653                 return FALSE;
2654             break;
2655         case XML_TEXT_NODE:
2656         case XML_CDATA_SECTION_NODE:
2657             return FALSE;
2658             break;
2659         default:
2660             break;
2661         }
2662     }
2663
2664     return root == 1;
2665 #endif
2666 }
2667
2668 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2669 {
2670     va_list ap;
2671     va_start(ap, msg);
2672     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2673     va_end(ap);
2674 }
2675
2676 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2677 {
2678     va_list ap;
2679     va_start(ap, msg);
2680     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2681     va_end(ap);
2682 }
2683
2684 static HRESULT WINAPI domdoc_validateNode(
2685     IXMLDOMDocument3* iface,
2686     IXMLDOMNode* node,
2687     IXMLDOMParseError** err)
2688 {
2689     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2690     LONG state, err_code = 0;
2691     HRESULT hr = S_OK;
2692     int validated = 0;
2693
2694     TRACE("(%p)->(%p, %p)\n", This, node, err);
2695     domdoc_get_readyState(iface, &state);
2696     if (state != READYSTATE_COMPLETE)
2697     {
2698         if (err)
2699            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2700         return E_PENDING;
2701     }
2702
2703     if (!node)
2704     {
2705         if (err)
2706             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2707         return E_POINTER;
2708     }
2709
2710     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2711     {
2712         if (err)
2713             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2714         return E_FAIL;
2715     }
2716
2717     if (!is_wellformed(get_doc(This)))
2718     {
2719         ERR("doc not well-formed\n");
2720         if (err)
2721             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2722         return S_FALSE;
2723     }
2724
2725     /* DTD validation */
2726     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2727     {
2728         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2729         vctx->error = validate_error;
2730         vctx->warning = validate_warning;
2731         ++validated;
2732
2733         if (!((node == (IXMLDOMNode*)iface)?
2734               xmlValidateDocument(vctx, get_doc(This)) :
2735               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2736         {
2737             /* TODO: get a real error code here */
2738             TRACE("DTD validation failed\n");
2739             err_code = E_XML_INVALID;
2740             hr = S_FALSE;
2741         }
2742         xmlFreeValidCtxt(vctx);
2743     }
2744
2745     /* Schema validation */
2746     if (hr == S_OK && This->properties->schemaCache != NULL)
2747     {
2748
2749         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2750         if (!FAILED(hr))
2751         {
2752             ++validated;
2753             /* TODO: get a real error code here */
2754             if (hr == S_OK)
2755             {
2756                 TRACE("schema validation succeeded\n");
2757             }
2758             else
2759             {
2760                 ERR("schema validation failed\n");
2761                 err_code = E_XML_INVALID;
2762             }
2763         }
2764         else
2765         {
2766             /* not really OK, just didn't find a schema for the ns */
2767             hr = S_OK;
2768         }
2769     }
2770
2771     if (!validated)
2772     {
2773         ERR("no DTD or schema found\n");
2774         err_code = E_XML_NODTD;
2775         hr = S_FALSE;
2776     }
2777
2778     if (err)
2779         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2780
2781     return hr;
2782 }
2783
2784 static HRESULT WINAPI domdoc_validate(
2785     IXMLDOMDocument3* iface,
2786     IXMLDOMParseError** err)
2787 {
2788     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2789     TRACE("(%p)->(%p)\n", This, err);
2790     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2791 }
2792
2793 static HRESULT WINAPI domdoc_setProperty(
2794     IXMLDOMDocument3* iface,
2795     BSTR p,
2796     VARIANT var)
2797 {
2798     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2799
2800     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2801
2802     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2803     {
2804         VARIANT varStr;
2805         HRESULT hr;
2806         BSTR bstr;
2807
2808         V_VT(&varStr) = VT_EMPTY;
2809         if (V_VT(&var) != VT_BSTR)
2810         {
2811             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2812                 return hr;
2813             bstr = V_BSTR(&varStr);
2814         }
2815         else
2816             bstr = V_BSTR(&var);
2817
2818         hr = S_OK;
2819         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2820             This->properties->XPath = TRUE;
2821         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2822             This->properties->XPath = FALSE;
2823         else
2824             hr = E_FAIL;
2825
2826         VariantClear(&varStr);
2827         return hr;
2828     }
2829     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2830     {
2831         VARIANT varStr;
2832         HRESULT hr;
2833         BSTR bstr;
2834         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2835         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2836         xmlXPathContextPtr ctx;
2837         struct list *pNsList;
2838         select_ns_entry* pNsEntry = NULL;
2839
2840         V_VT(&varStr) = VT_EMPTY;
2841         if (V_VT(&var) != VT_BSTR)
2842         {
2843             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2844                 return hr;
2845             bstr = V_BSTR(&varStr);
2846         }
2847         else
2848             bstr = V_BSTR(&var);
2849
2850         hr = S_OK;
2851
2852         pNsList = &(This->properties->selectNsList);
2853         clear_selectNsList(pNsList);
2854         heap_free(nsStr);
2855         nsStr = xmlchar_from_wchar(bstr);
2856
2857         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2858
2859         This->properties->selectNsStr = nsStr;
2860         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2861         if (bstr && *bstr)
2862         {
2863             ctx = xmlXPathNewContext(This->node.node->doc);
2864             pTokBegin = nsStr;
2865             pTokEnd = nsStr;
2866             for (; *pTokBegin; pTokBegin = pTokEnd)
2867             {
2868                 if (pNsEntry != NULL)
2869                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2870                 else
2871                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2872
2873                 while (*pTokBegin == ' ')
2874                     ++pTokBegin;
2875                 pTokEnd = pTokBegin;
2876                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2877                     ++pTokEnd;
2878
2879                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2880                 {
2881                     hr = E_FAIL;
2882                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2883                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2884                     continue;
2885                 }
2886
2887                 pTokBegin += 5;
2888                 if (*pTokBegin == '=')
2889                 {
2890                     /*valid for XSLPattern?*/
2891                     FIXME("Setting default xmlns not supported - skipping.\n");
2892                     pTokBegin = pTokEnd;
2893                     continue;
2894                 }
2895                 else if (*pTokBegin == ':')
2896                 {
2897                     pNsEntry->prefix = ++pTokBegin;
2898                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2899                         ;
2900
2901                     if (pTokInner == pTokEnd)
2902                     {
2903                         hr = E_FAIL;
2904                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2905                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2906                         continue;
2907                     }
2908
2909                     pNsEntry->prefix_end = *pTokInner;
2910                     *pTokInner = 0;
2911                     ++pTokInner;
2912
2913                     if (pTokEnd-pTokInner > 1 &&
2914                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2915                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2916                     {
2917                         pNsEntry->href = ++pTokInner;
2918                         pNsEntry->href_end = *(pTokEnd-1);
2919                         *(pTokEnd-1) = 0;
2920                         list_add_tail(pNsList, &pNsEntry->entry);
2921                         /*let libxml figure out if they're valid from here ;)*/
2922                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2923                         {
2924                             hr = E_FAIL;
2925                         }
2926                         pNsEntry = NULL;
2927                         continue;
2928                     }
2929                     else
2930                     {
2931                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2932                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2933                         list_add_tail(pNsList, &pNsEntry->entry);
2934
2935                         pNsEntry = NULL;
2936                         hr = E_FAIL;
2937                         continue;
2938                     }
2939                 }
2940                 else
2941                 {
2942                     hr = E_FAIL;
2943                     continue;
2944                 }
2945             }
2946             heap_free(pNsEntry);
2947             xmlXPathFreeContext(ctx);
2948         }
2949
2950         VariantClear(&varStr);
2951         return hr;
2952     }
2953     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2954              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2955              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2956     {
2957         /* Ignore */
2958         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2959         return S_OK;
2960     }
2961
2962     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2963     return E_FAIL;
2964 }
2965
2966 static HRESULT WINAPI domdoc_getProperty(
2967     IXMLDOMDocument3* iface,
2968     BSTR p,
2969     VARIANT* var)
2970 {
2971     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2972
2973     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2974
2975     if (!var)
2976         return E_INVALIDARG;
2977
2978     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2979     {
2980         V_VT(var) = VT_BSTR;
2981         V_BSTR(var) = This->properties->XPath ?
2982                       SysAllocString(PropValueXPathW) :
2983                       SysAllocString(PropValueXSLPatternW);
2984         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2985     }
2986     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2987     {
2988         int lenA, lenW;
2989         BSTR rebuiltStr, cur;
2990         const xmlChar *nsStr;
2991         struct list *pNsList;
2992         select_ns_entry* pNsEntry;
2993
2994         V_VT(var) = VT_BSTR;
2995         nsStr = This->properties->selectNsStr;
2996         pNsList = &This->properties->selectNsList;
2997         lenA = This->properties->selectNsStr_len;
2998         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2999         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3000         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3001         cur = rebuiltStr;
3002         /* this is fine because all of the chars that end tokens are ASCII*/
3003         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3004         {
3005             while (*cur != 0) ++cur;
3006             if (pNsEntry->prefix_end)
3007             {
3008                 *cur = pNsEntry->prefix_end;
3009                 while (*cur != 0) ++cur;
3010             }
3011
3012             if (pNsEntry->href_end)
3013             {
3014                 *cur = pNsEntry->href_end;
3015             }
3016         }
3017         V_BSTR(var) = SysAllocString(rebuiltStr);
3018         heap_free(rebuiltStr);
3019         return S_OK;
3020     }
3021
3022     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3023     return E_FAIL;
3024 }
3025
3026 static HRESULT WINAPI domdoc_importNode(
3027     IXMLDOMDocument3* iface,
3028     IXMLDOMNode* node,
3029     VARIANT_BOOL deep,
3030     IXMLDOMNode** clone)
3031 {
3032     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3033     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3034     return E_NOTIMPL;
3035 }
3036
3037 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3038 {
3039     domdoc_QueryInterface,
3040     domdoc_AddRef,
3041     domdoc_Release,
3042     domdoc_GetTypeInfoCount,
3043     domdoc_GetTypeInfo,
3044     domdoc_GetIDsOfNames,
3045     domdoc_Invoke,
3046     domdoc_get_nodeName,
3047     domdoc_get_nodeValue,
3048     domdoc_put_nodeValue,
3049     domdoc_get_nodeType,
3050     domdoc_get_parentNode,
3051     domdoc_get_childNodes,
3052     domdoc_get_firstChild,
3053     domdoc_get_lastChild,
3054     domdoc_get_previousSibling,
3055     domdoc_get_nextSibling,
3056     domdoc_get_attributes,
3057     domdoc_insertBefore,
3058     domdoc_replaceChild,
3059     domdoc_removeChild,
3060     domdoc_appendChild,
3061     domdoc_hasChildNodes,
3062     domdoc_get_ownerDocument,
3063     domdoc_cloneNode,
3064     domdoc_get_nodeTypeString,
3065     domdoc_get_text,
3066     domdoc_put_text,
3067     domdoc_get_specified,
3068     domdoc_get_definition,
3069     domdoc_get_nodeTypedValue,
3070     domdoc_put_nodeTypedValue,
3071     domdoc_get_dataType,
3072     domdoc_put_dataType,
3073     domdoc_get_xml,
3074     domdoc_transformNode,
3075     domdoc_selectNodes,
3076     domdoc_selectSingleNode,
3077     domdoc_get_parsed,
3078     domdoc_get_namespaceURI,
3079     domdoc_get_prefix,
3080     domdoc_get_baseName,
3081     domdoc_transformNodeToObject,
3082     domdoc_get_doctype,
3083     domdoc_get_implementation,
3084     domdoc_get_documentElement,
3085     domdoc_put_documentElement,
3086     domdoc_createElement,
3087     domdoc_createDocumentFragment,
3088     domdoc_createTextNode,
3089     domdoc_createComment,
3090     domdoc_createCDATASection,
3091     domdoc_createProcessingInstruction,
3092     domdoc_createAttribute,
3093     domdoc_createEntityReference,
3094     domdoc_getElementsByTagName,
3095     domdoc_createNode,
3096     domdoc_nodeFromID,
3097     domdoc_load,
3098     domdoc_get_readyState,
3099     domdoc_get_parseError,
3100     domdoc_get_url,
3101     domdoc_get_async,
3102     domdoc_put_async,
3103     domdoc_abort,
3104     domdoc_loadXML,
3105     domdoc_save,
3106     domdoc_get_validateOnParse,
3107     domdoc_put_validateOnParse,
3108     domdoc_get_resolveExternals,
3109     domdoc_put_resolveExternals,
3110     domdoc_get_preserveWhiteSpace,
3111     domdoc_put_preserveWhiteSpace,
3112     domdoc_put_onreadystatechange,
3113     domdoc_put_onDataAvailable,
3114     domdoc_put_onTransformNode,
3115     domdoc_get_namespaces,
3116     domdoc_get_schemas,
3117     domdoc_putref_schemas,
3118     domdoc_validate,
3119     domdoc_setProperty,
3120     domdoc_getProperty,
3121     domdoc_validateNode,
3122     domdoc_importNode
3123 };
3124
3125 /* IConnectionPointContainer */
3126 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3127                                                               REFIID riid, void **ppv)
3128 {
3129     domdoc *This = impl_from_IConnectionPointContainer(iface);
3130     return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3131 }
3132
3133 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3134 {
3135     domdoc *This = impl_from_IConnectionPointContainer(iface);
3136     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3137 }
3138
3139 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3140 {
3141     domdoc *This = impl_from_IConnectionPointContainer(iface);
3142     return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3143 }
3144
3145 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3146         IEnumConnectionPoints **ppEnum)
3147 {
3148     domdoc *This = impl_from_IConnectionPointContainer(iface);
3149     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3150     return E_NOTIMPL;
3151 }
3152
3153 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3154         REFIID riid, IConnectionPoint **cp)
3155 {
3156     domdoc *This = impl_from_IConnectionPointContainer(iface);
3157     ConnectionPoint *iter;
3158
3159     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3160
3161     *cp = NULL;
3162
3163     for(iter = This->cp_list; iter; iter = iter->next)
3164     {
3165         if (IsEqualGUID(iter->iid, riid))
3166             *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3167     }
3168
3169     if (*cp)
3170     {
3171         IConnectionPoint_AddRef(*cp);
3172         return S_OK;
3173     }
3174
3175     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3176     return CONNECT_E_NOCONNECTION;
3177
3178 }
3179
3180 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3181 {
3182     ConnectionPointContainer_QueryInterface,
3183     ConnectionPointContainer_AddRef,
3184     ConnectionPointContainer_Release,
3185     ConnectionPointContainer_EnumConnectionPoints,
3186     ConnectionPointContainer_FindConnectionPoint
3187 };
3188
3189 /* IConnectionPoint */
3190 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3191                                                      REFIID riid, void **ppv)
3192 {
3193     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3194
3195     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3196
3197     *ppv = NULL;
3198
3199     if (IsEqualGUID(&IID_IUnknown, riid) ||
3200         IsEqualGUID(&IID_IConnectionPoint, riid))
3201     {
3202         *ppv = iface;
3203     }
3204
3205     if (*ppv)
3206     {
3207         IConnectionPoint_AddRef(iface);
3208         return S_OK;
3209     }
3210
3211     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3212     return E_NOINTERFACE;
3213 }
3214
3215 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3216 {
3217     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3218     return IConnectionPointContainer_AddRef(This->container);
3219 }
3220
3221 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3222 {
3223     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3224     return IConnectionPointContainer_Release(This->container);
3225 }
3226
3227 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3228 {
3229     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3230
3231     TRACE("(%p)->(%p)\n", This, iid);
3232
3233     if (!iid) return E_POINTER;
3234
3235     *iid = *This->iid;
3236     return S_OK;
3237 }
3238
3239 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3240         IConnectionPointContainer **container)
3241 {
3242     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3243
3244     TRACE("(%p)->(%p)\n", This, container);
3245
3246     if (!container) return E_POINTER;
3247
3248     *container = This->container;
3249     IConnectionPointContainer_AddRef(*container);
3250     return S_OK;
3251 }
3252
3253 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3254                                              DWORD *pdwCookie)
3255 {
3256     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3257     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3258     return E_NOTIMPL;
3259 }
3260
3261 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3262 {
3263     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3264
3265     TRACE("(%p)->(%d)\n", This, cookie);
3266
3267     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3268         return CONNECT_E_NOCONNECTION;
3269
3270     IUnknown_Release(This->sinks[cookie-1].unk);
3271     This->sinks[cookie-1].unk = NULL;
3272
3273     return S_OK;
3274 }
3275
3276 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3277                                                       IEnumConnections **ppEnum)
3278 {
3279     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3280     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3281     return E_NOTIMPL;
3282 }
3283
3284 static const IConnectionPointVtbl ConnectionPointVtbl =
3285 {
3286     ConnectionPoint_QueryInterface,
3287     ConnectionPoint_AddRef,
3288     ConnectionPoint_Release,
3289     ConnectionPoint_GetConnectionInterface,
3290     ConnectionPoint_GetConnectionPointContainer,
3291     ConnectionPoint_Advise,
3292     ConnectionPoint_Unadvise,
3293     ConnectionPoint_EnumConnections
3294 };
3295
3296 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3297 {
3298     cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3299     cp->doc = doc;
3300     cp->iid = riid;
3301     cp->sinks = NULL;
3302     cp->sinks_size = 0;
3303
3304     cp->next = doc->cp_list;
3305     doc->cp_list = cp;
3306
3307     cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3308 }
3309
3310 /* domdoc implementation of IObjectWithSite */
3311 static HRESULT WINAPI
3312 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3313 {
3314     domdoc *This = impl_from_IObjectWithSite(iface);
3315     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3316 }
3317
3318 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3319 {
3320     domdoc *This = impl_from_IObjectWithSite(iface);
3321     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3322 }
3323
3324 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3325 {
3326     domdoc *This = impl_from_IObjectWithSite(iface);
3327     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3328 }
3329
3330 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3331 {
3332     domdoc *This = impl_from_IObjectWithSite(iface);
3333
3334     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3335
3336     if ( !This->site )
3337         return E_FAIL;
3338
3339     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3340 }
3341
3342 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3343 {
3344     domdoc *This = impl_from_IObjectWithSite(iface);
3345
3346     TRACE("(%p)->(%p)\n", iface, punk);
3347
3348     if(!punk)
3349     {
3350         if(This->site)
3351         {
3352             IUnknown_Release( This->site );
3353             This->site = NULL;
3354         }
3355
3356         return S_OK;
3357     }
3358
3359     IUnknown_AddRef( punk );
3360
3361     if(This->site)
3362         IUnknown_Release( This->site );
3363
3364     This->site = punk;
3365
3366     return S_OK;
3367 }
3368
3369 static const IObjectWithSiteVtbl domdocObjectSite =
3370 {
3371     domdoc_ObjectWithSite_QueryInterface,
3372     domdoc_ObjectWithSite_AddRef,
3373     domdoc_ObjectWithSite_Release,
3374     domdoc_ObjectWithSite_SetSite,
3375     domdoc_ObjectWithSite_GetSite
3376 };
3377
3378 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3379 {
3380     domdoc *This = impl_from_IObjectSafety(iface);
3381     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3382 }
3383
3384 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3385 {
3386     domdoc *This = impl_from_IObjectSafety(iface);
3387     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3388 }
3389
3390 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3391 {
3392     domdoc *This = impl_from_IObjectSafety(iface);
3393     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3394 }
3395
3396 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3397
3398 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3399         DWORD *supported, DWORD *enabled)
3400 {
3401     domdoc *This = impl_from_IObjectSafety(iface);
3402
3403     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3404
3405     if(!supported || !enabled) return E_POINTER;
3406
3407     *supported = SAFETY_SUPPORTED_OPTIONS;
3408     *enabled = This->safeopt;
3409
3410     return S_OK;
3411 }
3412
3413 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3414         DWORD mask, DWORD enabled)
3415 {
3416     domdoc *This = impl_from_IObjectSafety(iface);
3417     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3418
3419     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3420         return E_FAIL;
3421
3422     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3423     return S_OK;
3424 }
3425
3426 #undef SAFETY_SUPPORTED_OPTIONS
3427
3428 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3429     domdoc_Safety_QueryInterface,
3430     domdoc_Safety_AddRef,
3431     domdoc_Safety_Release,
3432     domdoc_Safety_GetInterfaceSafetyOptions,
3433     domdoc_Safety_SetInterfaceSafetyOptions
3434 };
3435
3436 static const tid_t domdoc_iface_tids[] = {
3437     IXMLDOMNode_tid,
3438     IXMLDOMDocument_tid,
3439     IXMLDOMDocument2_tid,
3440     0
3441 };
3442 static dispex_static_data_t domdoc_dispex = {
3443     NULL,
3444     IXMLDOMDocument2_tid,
3445     NULL,
3446     domdoc_iface_tids
3447 };
3448
3449 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3450 {
3451     domdoc *doc;
3452
3453     doc = heap_alloc( sizeof (*doc) );
3454     if( !doc )
3455         return E_OUTOFMEMORY;
3456
3457     doc->lpVtbl = &domdoc_vtbl;
3458     doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3459     doc->lpvtblIObjectWithSite = &domdocObjectSite;
3460     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3461     doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3462     doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3463     doc->ref = 1;
3464     doc->async = VARIANT_TRUE;
3465     doc->validating = 0;
3466     doc->resolving = 0;
3467     doc->properties = properties_from_xmlDocPtr(xmldoc);
3468     doc->error = S_OK;
3469     doc->stream = NULL;
3470     doc->site = NULL;
3471     doc->safeopt = 0;
3472     doc->bsc = NULL;
3473     doc->cp_list = NULL;
3474     memset(doc->events, 0, sizeof(doc->events));
3475
3476     /* events connection points */
3477     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3478     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3479     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3480
3481     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3482
3483     *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3484
3485     TRACE("returning iface %p\n", *document);
3486     return S_OK;
3487 }
3488
3489 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3490 {
3491     xmlDocPtr xmldoc;
3492     HRESULT hr;
3493
3494     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3495
3496     xmldoc = xmlNewDoc(NULL);
3497     if(!xmldoc)
3498         return E_OUTOFMEMORY;
3499
3500     xmldoc->_private = create_priv();
3501     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3502
3503     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3504     if(FAILED(hr))
3505     {
3506         free_properties(properties_from_xmlDocPtr(xmldoc));
3507         heap_free(xmldoc->_private);
3508         xmlFreeDoc(xmldoc);
3509         return hr;
3510     }
3511
3512     return hr;
3513 }
3514
3515 IUnknown* create_domdoc( xmlNodePtr document )
3516 {
3517     void* pObj = NULL;
3518     HRESULT hr;
3519
3520     TRACE("(%p)\n", document);
3521
3522     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3523     if (FAILED(hr))
3524         return NULL;
3525
3526     return pObj;
3527 }
3528
3529 #else
3530
3531 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3532 {
3533     MESSAGE("This program tried to use a DOMDocument object, but\n"
3534             "libxml2 support was not present at compile time.\n");
3535     return E_NOTIMPL;
3536 }
3537
3538 #endif