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