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