msxml3: Move string conversion helper to header.
[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* v )
1332 {
1333     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1334     TRACE("(%p)->(%p)\n", This, v);
1335     return return_null_var(v);
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** doctype )
1521 {
1522     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1523     IXMLDOMNode *node;
1524     xmlDtdPtr dtd;
1525     HRESULT hr;
1526
1527     TRACE("(%p)->(%p)\n", This, doctype);
1528
1529     if (!doctype) return E_INVALIDARG;
1530
1531     *doctype = NULL;
1532
1533     dtd = xmlGetIntSubset(get_doc(This));
1534     if (!dtd) return S_FALSE;
1535
1536     node = create_node((xmlNodePtr)dtd);
1537     if (!node) return S_FALSE;
1538
1539     hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1540     IXMLDOMNode_Release(node);
1541
1542     return hr;
1543 }
1544
1545
1546 static HRESULT WINAPI domdoc_get_implementation(
1547     IXMLDOMDocument3 *iface,
1548     IXMLDOMImplementation** impl )
1549 {
1550     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1551
1552     TRACE("(%p)->(%p)\n", This, impl);
1553
1554     if(!impl)
1555         return E_INVALIDARG;
1556
1557     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1558
1559     return S_OK;
1560 }
1561
1562 static HRESULT WINAPI domdoc_get_documentElement(
1563     IXMLDOMDocument3 *iface,
1564     IXMLDOMElement** DOMElement )
1565 {
1566     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1567     IXMLDOMNode *element_node;
1568     xmlNodePtr root;
1569     HRESULT hr;
1570
1571     TRACE("(%p)->(%p)\n", This, DOMElement);
1572
1573     if(!DOMElement)
1574         return E_INVALIDARG;
1575
1576     *DOMElement = NULL;
1577
1578     root = xmlDocGetRootElement( get_doc(This) );
1579     if ( !root )
1580         return S_FALSE;
1581
1582     element_node = create_node( root );
1583     if(!element_node) return S_FALSE;
1584
1585     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1586     IXMLDOMNode_Release(element_node);
1587
1588     return hr;
1589 }
1590
1591
1592 static HRESULT WINAPI domdoc_put_documentElement(
1593     IXMLDOMDocument3 *iface,
1594     IXMLDOMElement* DOMElement )
1595 {
1596     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1597     IXMLDOMNode *elementNode;
1598     xmlNodePtr oldRoot;
1599     xmlnode *xmlNode;
1600     HRESULT hr;
1601
1602     TRACE("(%p)->(%p)\n", This, DOMElement);
1603
1604     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1605     if(FAILED(hr))
1606         return hr;
1607
1608     xmlNode = get_node_obj( elementNode );
1609     if(!xmlNode) return E_FAIL;
1610
1611     if(!xmlNode->node->parent)
1612         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1613             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1614
1615     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1616     IXMLDOMNode_Release( elementNode );
1617
1618     if(oldRoot)
1619         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1620
1621     return S_OK;
1622 }
1623
1624
1625 static HRESULT WINAPI domdoc_createElement(
1626     IXMLDOMDocument3 *iface,
1627     BSTR tagname,
1628     IXMLDOMElement** element )
1629 {
1630     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1631     IXMLDOMNode *node;
1632     VARIANT type;
1633     HRESULT hr;
1634
1635     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1636
1637     if (!element || !tagname) return E_INVALIDARG;
1638
1639     V_VT(&type) = VT_I1;
1640     V_I1(&type) = NODE_ELEMENT;
1641
1642     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1643     if (hr == S_OK)
1644     {
1645         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1646         IXMLDOMNode_Release(node);
1647     }
1648
1649     return hr;
1650 }
1651
1652
1653 static HRESULT WINAPI domdoc_createDocumentFragment(
1654     IXMLDOMDocument3 *iface,
1655     IXMLDOMDocumentFragment** frag )
1656 {
1657     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1658     IXMLDOMNode *node;
1659     VARIANT type;
1660     HRESULT hr;
1661
1662     TRACE("(%p)->(%p)\n", This, frag);
1663
1664     if (!frag) return E_INVALIDARG;
1665
1666     *frag = NULL;
1667
1668     V_VT(&type) = VT_I1;
1669     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1670
1671     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1672     if (hr == S_OK)
1673     {
1674         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1675         IXMLDOMNode_Release(node);
1676     }
1677
1678     return hr;
1679 }
1680
1681
1682 static HRESULT WINAPI domdoc_createTextNode(
1683     IXMLDOMDocument3 *iface,
1684     BSTR data,
1685     IXMLDOMText** text )
1686 {
1687     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1688     IXMLDOMNode *node;
1689     VARIANT type;
1690     HRESULT hr;
1691
1692     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1693
1694     if (!text) return E_INVALIDARG;
1695
1696     *text = NULL;
1697
1698     V_VT(&type) = VT_I1;
1699     V_I1(&type) = NODE_TEXT;
1700
1701     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1702     if (hr == S_OK)
1703     {
1704         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1705         IXMLDOMNode_Release(node);
1706         hr = IXMLDOMText_put_data(*text, data);
1707     }
1708
1709     return hr;
1710 }
1711
1712
1713 static HRESULT WINAPI domdoc_createComment(
1714     IXMLDOMDocument3 *iface,
1715     BSTR data,
1716     IXMLDOMComment** comment )
1717 {
1718     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1719     VARIANT type;
1720     HRESULT hr;
1721     IXMLDOMNode *node;
1722
1723     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1724
1725     if (!comment) return E_INVALIDARG;
1726
1727     *comment = NULL;
1728
1729     V_VT(&type) = VT_I1;
1730     V_I1(&type) = NODE_COMMENT;
1731
1732     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1733     if (hr == S_OK)
1734     {
1735         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1736         IXMLDOMNode_Release(node);
1737         hr = IXMLDOMComment_put_data(*comment, data);
1738     }
1739
1740     return hr;
1741 }
1742
1743
1744 static HRESULT WINAPI domdoc_createCDATASection(
1745     IXMLDOMDocument3 *iface,
1746     BSTR data,
1747     IXMLDOMCDATASection** cdata )
1748 {
1749     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1750     IXMLDOMNode *node;
1751     VARIANT type;
1752     HRESULT hr;
1753
1754     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1755
1756     if (!cdata) return E_INVALIDARG;
1757
1758     *cdata = NULL;
1759
1760     V_VT(&type) = VT_I1;
1761     V_I1(&type) = NODE_CDATA_SECTION;
1762
1763     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1764     if (hr == S_OK)
1765     {
1766         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1767         IXMLDOMNode_Release(node);
1768         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1769     }
1770
1771     return hr;
1772 }
1773
1774
1775 static HRESULT WINAPI domdoc_createProcessingInstruction(
1776     IXMLDOMDocument3 *iface,
1777     BSTR target,
1778     BSTR data,
1779     IXMLDOMProcessingInstruction** pi )
1780 {
1781     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1782     IXMLDOMNode *node;
1783     VARIANT type;
1784     HRESULT hr;
1785
1786     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1787
1788     if (!pi) return E_INVALIDARG;
1789
1790     *pi = NULL;
1791
1792     V_VT(&type) = VT_I1;
1793     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1794
1795     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1796     if (hr == S_OK)
1797     {
1798         xmlnode *node_obj;
1799
1800         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1801         node_obj = get_node_obj(node);
1802         hr = node_set_content(node_obj, data);
1803
1804         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1805         IXMLDOMNode_Release(node);
1806     }
1807
1808     return hr;
1809 }
1810
1811
1812 static HRESULT WINAPI domdoc_createAttribute(
1813     IXMLDOMDocument3 *iface,
1814     BSTR name,
1815     IXMLDOMAttribute** attribute )
1816 {
1817     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1818     IXMLDOMNode *node;
1819     VARIANT type;
1820     HRESULT hr;
1821
1822     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1823
1824     if (!attribute || !name) return E_INVALIDARG;
1825
1826     V_VT(&type) = VT_I1;
1827     V_I1(&type) = NODE_ATTRIBUTE;
1828
1829     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1830     if (hr == S_OK)
1831     {
1832         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1833         IXMLDOMNode_Release(node);
1834     }
1835
1836     return hr;
1837 }
1838
1839
1840 static HRESULT WINAPI domdoc_createEntityReference(
1841     IXMLDOMDocument3 *iface,
1842     BSTR name,
1843     IXMLDOMEntityReference** entityref )
1844 {
1845     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1846     IXMLDOMNode *node;
1847     VARIANT type;
1848     HRESULT hr;
1849
1850     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1851
1852     if (!entityref) return E_INVALIDARG;
1853
1854     *entityref = NULL;
1855
1856     V_VT(&type) = VT_I1;
1857     V_I1(&type) = NODE_ENTITY_REFERENCE;
1858
1859     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1860     if (hr == S_OK)
1861     {
1862         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1863         IXMLDOMNode_Release(node);
1864     }
1865
1866     return hr;
1867 }
1868
1869 xmlChar* tagName_to_XPath(const BSTR tagName)
1870 {
1871     xmlChar *query, *tmp;
1872     static const xmlChar mod_pre[] = "*[local-name()='";
1873     static const xmlChar mod_post[] = "']";
1874     static const xmlChar prefix[] = "descendant::";
1875     const WCHAR *tokBegin, *tokEnd;
1876     int len;
1877
1878     query = xmlStrdup(prefix);
1879
1880     tokBegin = tagName;
1881     while (tokBegin && *tokBegin)
1882     {
1883         switch (*tokBegin)
1884         {
1885         case '/':
1886             query = xmlStrcat(query, BAD_CAST "/");
1887             ++tokBegin;
1888             break;
1889         case '*':
1890             query = xmlStrcat(query, BAD_CAST "*");
1891             ++tokBegin;
1892             break;
1893         default:
1894             query = xmlStrcat(query, mod_pre);
1895             tokEnd = tokBegin;
1896             while (*tokEnd && *tokEnd != '/')
1897                 ++tokEnd;
1898             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1899             tmp = xmlMalloc(len);
1900             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1901             query = xmlStrncat(query, tmp, len);
1902             xmlFree(tmp);
1903             tokBegin = tokEnd;
1904             query = xmlStrcat(query, mod_post);
1905         }
1906     }
1907
1908     return query;
1909 }
1910
1911 static HRESULT WINAPI domdoc_getElementsByTagName(
1912     IXMLDOMDocument3 *iface,
1913     BSTR tagName,
1914     IXMLDOMNodeList** resultList )
1915 {
1916     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1917     xmlChar *query;
1918     HRESULT hr;
1919     BOOL XPath;
1920
1921     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1922
1923     if (!tagName || !resultList) return E_INVALIDARG;
1924
1925     XPath = This->properties->XPath;
1926     This->properties->XPath = TRUE;
1927     query = tagName_to_XPath(tagName);
1928     hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
1929     xmlFree(query);
1930     This->properties->XPath = XPath;
1931
1932     return hr;
1933 }
1934
1935 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1936 {
1937     VARIANT tmp;
1938     HRESULT hr;
1939
1940     VariantInit(&tmp);
1941     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1942     if(FAILED(hr))
1943         return E_INVALIDARG;
1944
1945     *type = V_I4(&tmp);
1946
1947     return S_OK;
1948 }
1949
1950 static HRESULT WINAPI domdoc_createNode(
1951     IXMLDOMDocument3 *iface,
1952     VARIANT Type,
1953     BSTR name,
1954     BSTR namespaceURI,
1955     IXMLDOMNode** node )
1956 {
1957     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1958     DOMNodeType node_type;
1959     xmlNodePtr xmlnode;
1960     xmlChar *xml_name, *href;
1961     HRESULT hr;
1962
1963     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1964
1965     if(!node) return E_INVALIDARG;
1966
1967     hr = get_node_type(Type, &node_type);
1968     if(FAILED(hr)) return hr;
1969
1970     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1971         FIXME("nodes with namespaces currently not supported.\n");
1972
1973     TRACE("node_type %d\n", node_type);
1974
1975     /* exit earlier for types that need name */
1976     switch(node_type)
1977     {
1978     case NODE_ELEMENT:
1979     case NODE_ATTRIBUTE:
1980     case NODE_ENTITY_REFERENCE:
1981     case NODE_PROCESSING_INSTRUCTION:
1982         if (!name || *name == 0) return E_FAIL;
1983     default:
1984         break;
1985     }
1986
1987     xml_name = xmlchar_from_wchar(name);
1988     /* prevent empty href to be allocated */
1989     href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1990
1991     switch(node_type)
1992     {
1993     case NODE_ELEMENT:
1994     {
1995         xmlChar *local, *prefix;
1996
1997         local = xmlSplitQName2(xml_name, &prefix);
1998
1999         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2000
2001         /* allow to create default namespace xmlns= */
2002         if (local || (href && *href))
2003         {
2004             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2005             xmlSetNs(xmlnode, ns);
2006         }
2007
2008         xmlFree(local);
2009         xmlFree(prefix);
2010
2011         break;
2012     }
2013     case NODE_ATTRIBUTE:
2014         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
2015         break;
2016     case NODE_TEXT:
2017         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2018         break;
2019     case NODE_CDATA_SECTION:
2020         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2021         break;
2022     case NODE_ENTITY_REFERENCE:
2023         xmlnode = xmlNewReference(get_doc(This), xml_name);
2024         break;
2025     case NODE_PROCESSING_INSTRUCTION:
2026 #ifdef HAVE_XMLNEWDOCPI
2027         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2028 #else
2029         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2030         xmlnode = NULL;
2031 #endif
2032         break;
2033     case NODE_COMMENT:
2034         xmlnode = xmlNewDocComment(get_doc(This), NULL);
2035         break;
2036     case NODE_DOCUMENT_FRAGMENT:
2037         xmlnode = xmlNewDocFragment(get_doc(This));
2038         break;
2039     /* unsupported types */
2040     case NODE_DOCUMENT:
2041     case NODE_DOCUMENT_TYPE:
2042     case NODE_ENTITY:
2043     case NODE_NOTATION:
2044         heap_free(xml_name);
2045         return E_INVALIDARG;
2046     default:
2047         FIXME("unhandled node type %d\n", node_type);
2048         xmlnode = NULL;
2049         break;
2050     }
2051
2052     *node = create_node(xmlnode);
2053     heap_free(xml_name);
2054     heap_free(href);
2055
2056     if(*node)
2057     {
2058         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2059         xmldoc_add_orphan(xmlnode->doc, xmlnode);
2060         return S_OK;
2061     }
2062
2063     return E_FAIL;
2064 }
2065
2066 static HRESULT WINAPI domdoc_nodeFromID(
2067     IXMLDOMDocument3 *iface,
2068     BSTR idString,
2069     IXMLDOMNode** node )
2070 {
2071     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2072     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2073     return E_NOTIMPL;
2074 }
2075
2076 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2077 {
2078     domdoc *This = obj;
2079     xmlDocPtr xmldoc;
2080
2081     xmldoc = doparse(This, ptr, len, NULL);
2082     if(xmldoc) {
2083         xmldoc->_private = create_priv();
2084         return attach_xmldoc(This, xmldoc);
2085     }
2086
2087     return S_OK;
2088 }
2089
2090 static HRESULT doread( domdoc *This, LPWSTR filename )
2091 {
2092     bsc_t *bsc;
2093     HRESULT hr;
2094
2095     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2096     if(FAILED(hr))
2097         return hr;
2098
2099     if(This->bsc)
2100         detach_bsc(This->bsc);
2101
2102     This->bsc = bsc;
2103     return S_OK;
2104 }
2105
2106 static HRESULT WINAPI domdoc_load(
2107     IXMLDOMDocument3 *iface,
2108     VARIANT xmlSource,
2109     VARIANT_BOOL* isSuccessful )
2110 {
2111     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2112     LPWSTR filename = NULL;
2113     HRESULT hr = S_FALSE;
2114     IXMLDOMDocument3 *pNewDoc = NULL;
2115     IStream *pStream = NULL;
2116     xmlDocPtr xmldoc;
2117
2118     TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
2119
2120     *isSuccessful = VARIANT_FALSE;
2121
2122     assert( &This->node );
2123
2124     switch( V_VT(&xmlSource) )
2125     {
2126     case VT_BSTR:
2127         filename = V_BSTR(&xmlSource);
2128         break;
2129     case VT_UNKNOWN:
2130         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2131         if(hr == S_OK)
2132         {
2133             if(pNewDoc)
2134             {
2135                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2136                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2137                 hr = attach_xmldoc(This, xmldoc);
2138
2139                 if(SUCCEEDED(hr))
2140                     *isSuccessful = VARIANT_TRUE;
2141
2142                 return hr;
2143             }
2144         }
2145         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2146         if(hr == S_OK)
2147         {
2148             IPersistStream *pDocStream;
2149             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2150             if(hr == S_OK)
2151             {
2152                 hr = IPersistStream_Load(pDocStream, pStream);
2153                 IStream_Release(pStream);
2154                 if(hr == S_OK)
2155                 {
2156                     *isSuccessful = VARIANT_TRUE;
2157
2158                     TRACE("Using IStream to load Document\n");
2159                     return S_OK;
2160                 }
2161                 else
2162                 {
2163                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2164                 }
2165             }
2166             else
2167             {
2168                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2169             }
2170         }
2171         else
2172         {
2173             /* ISequentialStream */
2174             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2175         }
2176         break;
2177      default:
2178             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2179      }
2180
2181     TRACE("filename (%s)\n", debugstr_w(filename));
2182
2183     if ( filename )
2184     {
2185         hr = doread( This, filename );
2186
2187         if ( FAILED(hr) )
2188             This->error = E_FAIL;
2189         else
2190         {
2191             hr = This->error = S_OK;
2192             *isSuccessful = VARIANT_TRUE;
2193         }
2194     }
2195
2196     if(!filename || FAILED(hr)) {
2197         xmldoc = xmlNewDoc(NULL);
2198         xmldoc->_private = create_priv();
2199         hr = attach_xmldoc(This, xmldoc);
2200         if(SUCCEEDED(hr))
2201             hr = S_FALSE;
2202     }
2203
2204     TRACE("ret (%d)\n", hr);
2205
2206     return hr;
2207 }
2208
2209
2210 static HRESULT WINAPI domdoc_get_readyState(
2211     IXMLDOMDocument3 *iface,
2212     LONG *value )
2213 {
2214     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2215     FIXME("stub! (%p)->(%p)\n", This, value);
2216
2217     if (!value)
2218         return E_INVALIDARG;
2219
2220     *value = READYSTATE_COMPLETE;
2221     return S_OK;
2222 }
2223
2224
2225 static HRESULT WINAPI domdoc_get_parseError(
2226     IXMLDOMDocument3 *iface,
2227     IXMLDOMParseError** errorObj )
2228 {
2229     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2230     static const WCHAR err[] = {'e','r','r','o','r',0};
2231     BSTR error_string = NULL;
2232
2233     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2234
2235     if(This->error)
2236         error_string = SysAllocString(err);
2237
2238     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2239     if(!*errorObj) return E_OUTOFMEMORY;
2240     return S_OK;
2241 }
2242
2243
2244 static HRESULT WINAPI domdoc_get_url(
2245     IXMLDOMDocument3 *iface,
2246     BSTR* urlString )
2247 {
2248     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2249     FIXME("(%p)->(%p)\n", This, urlString);
2250     return E_NOTIMPL;
2251 }
2252
2253
2254 static HRESULT WINAPI domdoc_get_async(
2255     IXMLDOMDocument3 *iface,
2256     VARIANT_BOOL* isAsync )
2257 {
2258     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2259
2260     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2261     *isAsync = This->async;
2262     return S_OK;
2263 }
2264
2265
2266 static HRESULT WINAPI domdoc_put_async(
2267     IXMLDOMDocument3 *iface,
2268     VARIANT_BOOL isAsync )
2269 {
2270     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2271
2272     TRACE("(%p)->(%d)\n", This, isAsync);
2273     This->async = isAsync;
2274     return S_OK;
2275 }
2276
2277
2278 static HRESULT WINAPI domdoc_abort(
2279     IXMLDOMDocument3 *iface )
2280 {
2281     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2282     FIXME("%p\n", This);
2283     return E_NOTIMPL;
2284 }
2285
2286
2287 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2288 {
2289     UINT len;
2290     LPSTR str;
2291
2292     len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2293     str = heap_alloc( len );
2294     if ( !str )
2295         return FALSE;
2296     WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2297     *plen = len;
2298     *pstr = str;
2299     return TRUE;
2300 }
2301
2302 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2303 static HRESULT WINAPI domdoc_loadXML(
2304     IXMLDOMDocument3 *iface,
2305     BSTR bstrXML,
2306     VARIANT_BOOL* isSuccessful )
2307 {
2308     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2309     static const xmlChar encoding[] = "UTF-8";
2310     xmlDocPtr xmldoc = NULL;
2311     HRESULT hr = S_FALSE, hr2;
2312     char *str;
2313     int len;
2314
2315     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2316
2317     assert ( &This->node );
2318
2319     if ( isSuccessful )
2320     {
2321         *isSuccessful = VARIANT_FALSE;
2322
2323         if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2324         {
2325             xmldoc = doparse(This, str, len, encoding);
2326             heap_free( str );
2327             if ( !xmldoc )
2328             {
2329                 This->error = E_FAIL;
2330                 TRACE("failed to parse document\n");
2331             }
2332             else
2333             {
2334                 hr = This->error = S_OK;
2335                 *isSuccessful = VARIANT_TRUE;
2336                 TRACE("parsed document %p\n", xmldoc);
2337             }
2338         }
2339     }
2340     if(!xmldoc)
2341         xmldoc = xmlNewDoc(NULL);
2342
2343     xmldoc->_private = create_priv();
2344
2345     hr2 = attach_xmldoc(This, xmldoc);
2346     if( FAILED(hr2) )
2347         hr = hr2;
2348
2349     return hr;
2350 }
2351
2352 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2353 {
2354     DWORD written = -1;
2355
2356     if(!WriteFile(ctx, buffer, len, &written, NULL))
2357     {
2358         WARN("write error\n");
2359         return -1;
2360     }
2361     else
2362         return written;
2363 }
2364
2365 static int XMLCALL domdoc_save_closecallback(void *ctx)
2366 {
2367     return CloseHandle(ctx) ? 0 : -1;
2368 }
2369
2370 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2371 {
2372     ULONG written = 0;
2373     HRESULT hr;
2374
2375     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2376     if (hr != S_OK)
2377     {
2378         WARN("stream write error: 0x%08x\n", hr);
2379         return -1;
2380     }
2381     else
2382         return written;
2383 }
2384
2385 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2386 {
2387     IStream_Release((IStream*)ctx);
2388     return 0;
2389 }
2390
2391 static HRESULT WINAPI domdoc_save(
2392     IXMLDOMDocument3 *iface,
2393     VARIANT destination )
2394 {
2395     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2396     xmlSaveCtxtPtr ctx = NULL;
2397     xmlNodePtr xmldecl;
2398     HRESULT ret = S_OK;
2399
2400     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2401           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2402
2403     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2404     {
2405         FIXME("Unhandled vt %d\n", V_VT(&destination));
2406         return S_FALSE;
2407     }
2408
2409     if(V_VT(&destination) == VT_UNKNOWN)
2410     {
2411         IUnknown *pUnk = V_UNKNOWN(&destination);
2412         IXMLDOMDocument2 *document;
2413         IStream *stream;
2414
2415         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2416         if(ret == S_OK)
2417         {
2418             VARIANT_BOOL success;
2419             BSTR xml;
2420
2421             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2422             if(ret == S_OK)
2423             {
2424                 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2425                 SysFreeString(xml);
2426             }
2427
2428             IXMLDOMDocument3_Release(document);
2429             return ret;
2430         }
2431
2432         ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2433         if(ret == S_OK)
2434         {
2435             ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2436                 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2437
2438             if(!ctx)
2439             {
2440                 IStream_Release(stream);
2441                 return E_FAIL;
2442             }
2443         }
2444     }
2445     else
2446     {
2447         /* save with file path */
2448         HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2449                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2450         if( handle == INVALID_HANDLE_VALUE )
2451         {
2452             WARN("failed to create file\n");
2453             return E_FAIL;
2454         }
2455
2456         /* disable top XML declaration */
2457         ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2458                           handle, NULL, XML_SAVE_NO_DECL);
2459         if (!ctx)
2460         {
2461             CloseHandle(handle);
2462             return E_FAIL;
2463         }
2464     }
2465
2466     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2467     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2468     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2469
2470     /* will release resources through close callback */
2471     xmlSaveClose(ctx);
2472
2473     return ret;
2474 }
2475
2476 static HRESULT WINAPI domdoc_get_validateOnParse(
2477     IXMLDOMDocument3 *iface,
2478     VARIANT_BOOL* isValidating )
2479 {
2480     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2481     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2482     *isValidating = This->validating;
2483     return S_OK;
2484 }
2485
2486
2487 static HRESULT WINAPI domdoc_put_validateOnParse(
2488     IXMLDOMDocument3 *iface,
2489     VARIANT_BOOL isValidating )
2490 {
2491     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492     TRACE("(%p)->(%d)\n", This, isValidating);
2493     This->validating = isValidating;
2494     return S_OK;
2495 }
2496
2497
2498 static HRESULT WINAPI domdoc_get_resolveExternals(
2499     IXMLDOMDocument3 *iface,
2500     VARIANT_BOOL* isResolving )
2501 {
2502     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2503     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2504     *isResolving = This->resolving;
2505     return S_OK;
2506 }
2507
2508
2509 static HRESULT WINAPI domdoc_put_resolveExternals(
2510     IXMLDOMDocument3 *iface,
2511     VARIANT_BOOL isResolving )
2512 {
2513     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514     TRACE("(%p)->(%d)\n", This, isResolving);
2515     This->resolving = isResolving;
2516     return S_OK;
2517 }
2518
2519
2520 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2521     IXMLDOMDocument3 *iface,
2522     VARIANT_BOOL* isPreserving )
2523 {
2524     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2525     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2526     *isPreserving = This->properties->preserving;
2527     return S_OK;
2528 }
2529
2530
2531 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2532     IXMLDOMDocument3 *iface,
2533     VARIANT_BOOL isPreserving )
2534 {
2535     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2536     TRACE("(%p)->(%d)\n", This, isPreserving);
2537     This->properties->preserving = isPreserving;
2538     return S_OK;
2539 }
2540
2541
2542 static HRESULT WINAPI domdoc_put_onreadystatechange(
2543     IXMLDOMDocument3 *iface,
2544     VARIANT event )
2545 {
2546     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2547
2548     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2549     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2550 }
2551
2552
2553 static HRESULT WINAPI domdoc_put_onDataAvailable(
2554     IXMLDOMDocument3 *iface,
2555     VARIANT onDataAvailableSink )
2556 {
2557     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2558     FIXME("%p\n", This);
2559     return E_NOTIMPL;
2560 }
2561
2562 static HRESULT WINAPI domdoc_put_onTransformNode(
2563     IXMLDOMDocument3 *iface,
2564     VARIANT onTransformNodeSink )
2565 {
2566     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2567     FIXME("%p\n", This);
2568     return E_NOTIMPL;
2569 }
2570
2571 static HRESULT WINAPI domdoc_get_namespaces(
2572     IXMLDOMDocument3* iface,
2573     IXMLDOMSchemaCollection** schemaCollection )
2574 {
2575     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2576     FIXME("(%p)->(%p)\n", This, schemaCollection);
2577     return E_NOTIMPL;
2578 }
2579
2580 static HRESULT WINAPI domdoc_get_schemas(
2581     IXMLDOMDocument3* iface,
2582     VARIANT* var1 )
2583 {
2584     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2585     HRESULT hr = S_FALSE;
2586     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2587
2588     TRACE("(%p)->(%p)\n", This, var1);
2589
2590     VariantInit(var1); /* Test shows we don't call VariantClear here */
2591     V_VT(var1) = VT_NULL;
2592
2593     if(cur_schema)
2594     {
2595         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2596         if(SUCCEEDED(hr))
2597             V_VT(var1) = VT_DISPATCH;
2598     }
2599     return hr;
2600 }
2601
2602 static HRESULT WINAPI domdoc_putref_schemas(
2603     IXMLDOMDocument3* iface,
2604     VARIANT var1)
2605 {
2606     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2607     HRESULT hr = E_FAIL;
2608     IXMLDOMSchemaCollection2* new_schema = NULL;
2609
2610     FIXME("(%p): semi-stub\n", This);
2611     switch(V_VT(&var1))
2612     {
2613     case VT_UNKNOWN:
2614         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2615         break;
2616
2617     case VT_DISPATCH:
2618         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2619         break;
2620
2621     case VT_NULL:
2622     case VT_EMPTY:
2623         hr = S_OK;
2624         break;
2625
2626     default:
2627         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2628     }
2629
2630     if(SUCCEEDED(hr))
2631     {
2632         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2633         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2634     }
2635
2636     return hr;
2637 }
2638
2639 static inline BOOL is_wellformed(xmlDocPtr doc)
2640 {
2641 #ifdef HAVE_XMLDOC_PROPERTIES
2642     return doc->properties & XML_DOC_WELLFORMED;
2643 #else
2644     /* Not a full check, but catches the worst violations */
2645     xmlNodePtr child;
2646     int root = 0;
2647
2648     for (child = doc->children; child != NULL; child = child->next)
2649     {
2650         switch (child->type)
2651         {
2652         case XML_ELEMENT_NODE:
2653             if (++root > 1)
2654                 return FALSE;
2655             break;
2656         case XML_TEXT_NODE:
2657         case XML_CDATA_SECTION_NODE:
2658             return FALSE;
2659             break;
2660         default:
2661             break;
2662         }
2663     }
2664
2665     return root == 1;
2666 #endif
2667 }
2668
2669 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2670 {
2671     va_list ap;
2672     va_start(ap, msg);
2673     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2674     va_end(ap);
2675 }
2676
2677 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2678 {
2679     va_list ap;
2680     va_start(ap, msg);
2681     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2682     va_end(ap);
2683 }
2684
2685 static HRESULT WINAPI domdoc_validateNode(
2686     IXMLDOMDocument3* iface,
2687     IXMLDOMNode* node,
2688     IXMLDOMParseError** err)
2689 {
2690     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2691     LONG state, err_code = 0;
2692     HRESULT hr = S_OK;
2693     int validated = 0;
2694
2695     TRACE("(%p)->(%p, %p)\n", This, node, err);
2696     domdoc_get_readyState(iface, &state);
2697     if (state != READYSTATE_COMPLETE)
2698     {
2699         if (err)
2700            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2701         return E_PENDING;
2702     }
2703
2704     if (!node)
2705     {
2706         if (err)
2707             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2708         return E_POINTER;
2709     }
2710
2711     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2712     {
2713         if (err)
2714             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2715         return E_FAIL;
2716     }
2717
2718     if (!is_wellformed(get_doc(This)))
2719     {
2720         ERR("doc not well-formed\n");
2721         if (err)
2722             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2723         return S_FALSE;
2724     }
2725
2726     /* DTD validation */
2727     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2728     {
2729         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2730         vctx->error = validate_error;
2731         vctx->warning = validate_warning;
2732         ++validated;
2733
2734         if (!((node == (IXMLDOMNode*)iface)?
2735               xmlValidateDocument(vctx, get_doc(This)) :
2736               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2737         {
2738             /* TODO: get a real error code here */
2739             TRACE("DTD validation failed\n");
2740             err_code = E_XML_INVALID;
2741             hr = S_FALSE;
2742         }
2743         xmlFreeValidCtxt(vctx);
2744     }
2745
2746     /* Schema validation */
2747     if (hr == S_OK && This->properties->schemaCache != NULL)
2748     {
2749
2750         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2751         if (!FAILED(hr))
2752         {
2753             ++validated;
2754             /* TODO: get a real error code here */
2755             if (hr == S_OK)
2756             {
2757                 TRACE("schema validation succeeded\n");
2758             }
2759             else
2760             {
2761                 ERR("schema validation failed\n");
2762                 err_code = E_XML_INVALID;
2763             }
2764         }
2765         else
2766         {
2767             /* not really OK, just didn't find a schema for the ns */
2768             hr = S_OK;
2769         }
2770     }
2771
2772     if (!validated)
2773     {
2774         ERR("no DTD or schema found\n");
2775         err_code = E_XML_NODTD;
2776         hr = S_FALSE;
2777     }
2778
2779     if (err)
2780         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2781
2782     return hr;
2783 }
2784
2785 static HRESULT WINAPI domdoc_validate(
2786     IXMLDOMDocument3* iface,
2787     IXMLDOMParseError** err)
2788 {
2789     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2790     TRACE("(%p)->(%p)\n", This, err);
2791     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2792 }
2793
2794 static HRESULT WINAPI domdoc_setProperty(
2795     IXMLDOMDocument3* iface,
2796     BSTR p,
2797     VARIANT var)
2798 {
2799     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2800
2801     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2802
2803     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2804     {
2805         VARIANT varStr;
2806         HRESULT hr;
2807         BSTR bstr;
2808
2809         V_VT(&varStr) = VT_EMPTY;
2810         if (V_VT(&var) != VT_BSTR)
2811         {
2812             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2813                 return hr;
2814             bstr = V_BSTR(&varStr);
2815         }
2816         else
2817             bstr = V_BSTR(&var);
2818
2819         hr = S_OK;
2820         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2821             This->properties->XPath = TRUE;
2822         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2823             This->properties->XPath = FALSE;
2824         else
2825             hr = E_FAIL;
2826
2827         VariantClear(&varStr);
2828         return hr;
2829     }
2830     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2831     {
2832         VARIANT varStr;
2833         HRESULT hr;
2834         BSTR bstr;
2835         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2836         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2837         xmlXPathContextPtr ctx;
2838         struct list *pNsList;
2839         select_ns_entry* pNsEntry = NULL;
2840
2841         V_VT(&varStr) = VT_EMPTY;
2842         if (V_VT(&var) != VT_BSTR)
2843         {
2844             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2845                 return hr;
2846             bstr = V_BSTR(&varStr);
2847         }
2848         else
2849             bstr = V_BSTR(&var);
2850
2851         hr = S_OK;
2852
2853         pNsList = &(This->properties->selectNsList);
2854         clear_selectNsList(pNsList);
2855         heap_free(nsStr);
2856         nsStr = xmlchar_from_wchar(bstr);
2857
2858         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2859
2860         This->properties->selectNsStr = nsStr;
2861         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2862         if (bstr && *bstr)
2863         {
2864             ctx = xmlXPathNewContext(This->node.node->doc);
2865             pTokBegin = nsStr;
2866             pTokEnd = nsStr;
2867             for (; *pTokBegin; pTokBegin = pTokEnd)
2868             {
2869                 if (pNsEntry != NULL)
2870                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2871                 else
2872                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2873
2874                 while (*pTokBegin == ' ')
2875                     ++pTokBegin;
2876                 pTokEnd = pTokBegin;
2877                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2878                     ++pTokEnd;
2879
2880                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2881                 {
2882                     hr = E_FAIL;
2883                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2884                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2885                     continue;
2886                 }
2887
2888                 pTokBegin += 5;
2889                 if (*pTokBegin == '=')
2890                 {
2891                     /*valid for XSLPattern?*/
2892                     FIXME("Setting default xmlns not supported - skipping.\n");
2893                     pTokBegin = pTokEnd;
2894                     continue;
2895                 }
2896                 else if (*pTokBegin == ':')
2897                 {
2898                     pNsEntry->prefix = ++pTokBegin;
2899                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2900                         ;
2901
2902                     if (pTokInner == pTokEnd)
2903                     {
2904                         hr = E_FAIL;
2905                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2906                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2907                         continue;
2908                     }
2909
2910                     pNsEntry->prefix_end = *pTokInner;
2911                     *pTokInner = 0;
2912                     ++pTokInner;
2913
2914                     if (pTokEnd-pTokInner > 1 &&
2915                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2916                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2917                     {
2918                         pNsEntry->href = ++pTokInner;
2919                         pNsEntry->href_end = *(pTokEnd-1);
2920                         *(pTokEnd-1) = 0;
2921                         list_add_tail(pNsList, &pNsEntry->entry);
2922                         /*let libxml figure out if they're valid from here ;)*/
2923                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2924                         {
2925                             hr = E_FAIL;
2926                         }
2927                         pNsEntry = NULL;
2928                         continue;
2929                     }
2930                     else
2931                     {
2932                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2933                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2934                         list_add_tail(pNsList, &pNsEntry->entry);
2935
2936                         pNsEntry = NULL;
2937                         hr = E_FAIL;
2938                         continue;
2939                     }
2940                 }
2941                 else
2942                 {
2943                     hr = E_FAIL;
2944                     continue;
2945                 }
2946             }
2947             heap_free(pNsEntry);
2948             xmlXPathFreeContext(ctx);
2949         }
2950
2951         VariantClear(&varStr);
2952         return hr;
2953     }
2954     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2955              lstrcmpiW(p, PropertyNewParserW) == 0)
2956     {
2957         /* Ignore */
2958         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2959         return S_OK;
2960     }
2961
2962     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2963     return E_FAIL;
2964 }
2965
2966 static HRESULT WINAPI domdoc_getProperty(
2967     IXMLDOMDocument3* iface,
2968     BSTR p,
2969     VARIANT* var)
2970 {
2971     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2972
2973     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2974
2975     if (!var)
2976         return E_INVALIDARG;
2977
2978     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2979     {
2980         V_VT(var) = VT_BSTR;
2981         V_BSTR(var) = This->properties->XPath ?
2982                       SysAllocString(PropValueXPathW) :
2983                       SysAllocString(PropValueXSLPatternW);
2984         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2985     }
2986     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2987     {
2988         int lenA, lenW;
2989         BSTR rebuiltStr, cur;
2990         const xmlChar *nsStr;
2991         struct list *pNsList;
2992         select_ns_entry* pNsEntry;
2993
2994         V_VT(var) = VT_BSTR;
2995         nsStr = This->properties->selectNsStr;
2996         pNsList = &This->properties->selectNsList;
2997         lenA = This->properties->selectNsStr_len;
2998         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2999         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3000         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3001         cur = rebuiltStr;
3002         /* this is fine because all of the chars that end tokens are ASCII*/
3003         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3004         {
3005             while (*cur != 0) ++cur;
3006             if (pNsEntry->prefix_end)
3007             {
3008                 *cur = pNsEntry->prefix_end;
3009                 while (*cur != 0) ++cur;
3010             }
3011
3012             if (pNsEntry->href_end)
3013             {
3014                 *cur = pNsEntry->href_end;
3015             }
3016         }
3017         V_BSTR(var) = SysAllocString(rebuiltStr);
3018         heap_free(rebuiltStr);
3019         return S_OK;
3020     }
3021
3022     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3023     return E_FAIL;
3024 }
3025
3026 static HRESULT WINAPI domdoc_importNode(
3027     IXMLDOMDocument3* iface,
3028     IXMLDOMNode* node,
3029     VARIANT_BOOL deep,
3030     IXMLDOMNode** clone)
3031 {
3032     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3033     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3034     return E_NOTIMPL;
3035 }
3036
3037 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3038 {
3039     domdoc_QueryInterface,
3040     domdoc_AddRef,
3041     domdoc_Release,
3042     domdoc_GetTypeInfoCount,
3043     domdoc_GetTypeInfo,
3044     domdoc_GetIDsOfNames,
3045     domdoc_Invoke,
3046     domdoc_get_nodeName,
3047     domdoc_get_nodeValue,
3048     domdoc_put_nodeValue,
3049     domdoc_get_nodeType,
3050     domdoc_get_parentNode,
3051     domdoc_get_childNodes,
3052     domdoc_get_firstChild,
3053     domdoc_get_lastChild,
3054     domdoc_get_previousSibling,
3055     domdoc_get_nextSibling,
3056     domdoc_get_attributes,
3057     domdoc_insertBefore,
3058     domdoc_replaceChild,
3059     domdoc_removeChild,
3060     domdoc_appendChild,
3061     domdoc_hasChildNodes,
3062     domdoc_get_ownerDocument,
3063     domdoc_cloneNode,
3064     domdoc_get_nodeTypeString,
3065     domdoc_get_text,
3066     domdoc_put_text,
3067     domdoc_get_specified,
3068     domdoc_get_definition,
3069     domdoc_get_nodeTypedValue,
3070     domdoc_put_nodeTypedValue,
3071     domdoc_get_dataType,
3072     domdoc_put_dataType,
3073     domdoc_get_xml,
3074     domdoc_transformNode,
3075     domdoc_selectNodes,
3076     domdoc_selectSingleNode,
3077     domdoc_get_parsed,
3078     domdoc_get_namespaceURI,
3079     domdoc_get_prefix,
3080     domdoc_get_baseName,
3081     domdoc_transformNodeToObject,
3082     domdoc_get_doctype,
3083     domdoc_get_implementation,
3084     domdoc_get_documentElement,
3085     domdoc_put_documentElement,
3086     domdoc_createElement,
3087     domdoc_createDocumentFragment,
3088     domdoc_createTextNode,
3089     domdoc_createComment,
3090     domdoc_createCDATASection,
3091     domdoc_createProcessingInstruction,
3092     domdoc_createAttribute,
3093     domdoc_createEntityReference,
3094     domdoc_getElementsByTagName,
3095     domdoc_createNode,
3096     domdoc_nodeFromID,
3097     domdoc_load,
3098     domdoc_get_readyState,
3099     domdoc_get_parseError,
3100     domdoc_get_url,
3101     domdoc_get_async,
3102     domdoc_put_async,
3103     domdoc_abort,
3104     domdoc_loadXML,
3105     domdoc_save,
3106     domdoc_get_validateOnParse,
3107     domdoc_put_validateOnParse,
3108     domdoc_get_resolveExternals,
3109     domdoc_put_resolveExternals,
3110     domdoc_get_preserveWhiteSpace,
3111     domdoc_put_preserveWhiteSpace,
3112     domdoc_put_onreadystatechange,
3113     domdoc_put_onDataAvailable,
3114     domdoc_put_onTransformNode,
3115     domdoc_get_namespaces,
3116     domdoc_get_schemas,
3117     domdoc_putref_schemas,
3118     domdoc_validate,
3119     domdoc_setProperty,
3120     domdoc_getProperty,
3121     domdoc_validateNode,
3122     domdoc_importNode
3123 };
3124
3125 /* IConnectionPointContainer */
3126 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3127                                                               REFIID riid, void **ppv)
3128 {
3129     domdoc *This = impl_from_IConnectionPointContainer(iface);
3130     return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3131 }
3132
3133 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3134 {
3135     domdoc *This = impl_from_IConnectionPointContainer(iface);
3136     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3137 }
3138
3139 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3140 {
3141     domdoc *This = impl_from_IConnectionPointContainer(iface);
3142     return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3143 }
3144
3145 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3146         IEnumConnectionPoints **ppEnum)
3147 {
3148     domdoc *This = impl_from_IConnectionPointContainer(iface);
3149     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3150     return E_NOTIMPL;
3151 }
3152
3153 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3154         REFIID riid, IConnectionPoint **cp)
3155 {
3156     domdoc *This = impl_from_IConnectionPointContainer(iface);
3157     ConnectionPoint *iter;
3158
3159     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3160
3161     *cp = NULL;
3162
3163     for(iter = This->cp_list; iter; iter = iter->next)
3164     {
3165         if (IsEqualGUID(iter->iid, riid))
3166             *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3167     }
3168
3169     if (*cp)
3170     {
3171         IConnectionPoint_AddRef(*cp);
3172         return S_OK;
3173     }
3174
3175     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3176     return CONNECT_E_NOCONNECTION;
3177
3178 }
3179
3180 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3181 {
3182     ConnectionPointContainer_QueryInterface,
3183     ConnectionPointContainer_AddRef,
3184     ConnectionPointContainer_Release,
3185     ConnectionPointContainer_EnumConnectionPoints,
3186     ConnectionPointContainer_FindConnectionPoint
3187 };
3188
3189 /* IConnectionPoint */
3190 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3191                                                      REFIID riid, void **ppv)
3192 {
3193     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3194
3195     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3196
3197     *ppv = NULL;
3198
3199     if (IsEqualGUID(&IID_IUnknown, riid) ||
3200         IsEqualGUID(&IID_IConnectionPoint, riid))
3201     {
3202         *ppv = iface;
3203     }
3204
3205     if (*ppv)
3206     {
3207         IConnectionPoint_AddRef(iface);
3208         return S_OK;
3209     }
3210
3211     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3212     return E_NOINTERFACE;
3213 }
3214
3215 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3216 {
3217     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3218     return IConnectionPointContainer_AddRef(This->container);
3219 }
3220
3221 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3222 {
3223     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3224     return IConnectionPointContainer_Release(This->container);
3225 }
3226
3227 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3228 {
3229     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3230
3231     TRACE("(%p)->(%p)\n", This, iid);
3232
3233     if (!iid) return E_POINTER;
3234
3235     *iid = *This->iid;
3236     return S_OK;
3237 }
3238
3239 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3240         IConnectionPointContainer **container)
3241 {
3242     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3243
3244     TRACE("(%p)->(%p)\n", This, container);
3245
3246     if (!container) return E_POINTER;
3247
3248     *container = This->container;
3249     IConnectionPointContainer_AddRef(*container);
3250     return S_OK;
3251 }
3252
3253 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3254                                              DWORD *pdwCookie)
3255 {
3256     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3257     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3258     return E_NOTIMPL;
3259 }
3260
3261 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3262 {
3263     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3264
3265     TRACE("(%p)->(%d)\n", This, cookie);
3266
3267     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3268         return CONNECT_E_NOCONNECTION;
3269
3270     IUnknown_Release(This->sinks[cookie-1].unk);
3271     This->sinks[cookie-1].unk = NULL;
3272
3273     return S_OK;
3274 }
3275
3276 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3277                                                       IEnumConnections **ppEnum)
3278 {
3279     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3280     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3281     return E_NOTIMPL;
3282 }
3283
3284 static const IConnectionPointVtbl ConnectionPointVtbl =
3285 {
3286     ConnectionPoint_QueryInterface,
3287     ConnectionPoint_AddRef,
3288     ConnectionPoint_Release,
3289     ConnectionPoint_GetConnectionInterface,
3290     ConnectionPoint_GetConnectionPointContainer,
3291     ConnectionPoint_Advise,
3292     ConnectionPoint_Unadvise,
3293     ConnectionPoint_EnumConnections
3294 };
3295
3296 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3297 {
3298     cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3299     cp->doc = doc;
3300     cp->iid = riid;
3301     cp->sinks = NULL;
3302     cp->sinks_size = 0;
3303
3304     cp->next = doc->cp_list;
3305     doc->cp_list = cp;
3306
3307     cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3308 }
3309
3310 /* domdoc implementation of IObjectWithSite */
3311 static HRESULT WINAPI
3312 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3313 {
3314     domdoc *This = impl_from_IObjectWithSite(iface);
3315     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3316 }
3317
3318 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3319 {
3320     domdoc *This = impl_from_IObjectWithSite(iface);
3321     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3322 }
3323
3324 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3325 {
3326     domdoc *This = impl_from_IObjectWithSite(iface);
3327     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3328 }
3329
3330 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3331 {
3332     domdoc *This = impl_from_IObjectWithSite(iface);
3333
3334     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3335
3336     if ( !This->site )
3337         return E_FAIL;
3338
3339     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3340 }
3341
3342 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3343 {
3344     domdoc *This = impl_from_IObjectWithSite(iface);
3345
3346     TRACE("(%p)->(%p)\n", iface, punk);
3347
3348     if(!punk)
3349     {
3350         if(This->site)
3351         {
3352             IUnknown_Release( This->site );
3353             This->site = NULL;
3354         }
3355
3356         return S_OK;
3357     }
3358
3359     IUnknown_AddRef( punk );
3360
3361     if(This->site)
3362         IUnknown_Release( This->site );
3363
3364     This->site = punk;
3365
3366     return S_OK;
3367 }
3368
3369 static const IObjectWithSiteVtbl domdocObjectSite =
3370 {
3371     domdoc_ObjectWithSite_QueryInterface,
3372     domdoc_ObjectWithSite_AddRef,
3373     domdoc_ObjectWithSite_Release,
3374     domdoc_ObjectWithSite_SetSite,
3375     domdoc_ObjectWithSite_GetSite
3376 };
3377
3378 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3379 {
3380     domdoc *This = impl_from_IObjectSafety(iface);
3381     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3382 }
3383
3384 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3385 {
3386     domdoc *This = impl_from_IObjectSafety(iface);
3387     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3388 }
3389
3390 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3391 {
3392     domdoc *This = impl_from_IObjectSafety(iface);
3393     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3394 }
3395
3396 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3397
3398 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3399         DWORD *supported, DWORD *enabled)
3400 {
3401     domdoc *This = impl_from_IObjectSafety(iface);
3402
3403     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3404
3405     if(!supported || !enabled) return E_POINTER;
3406
3407     *supported = SAFETY_SUPPORTED_OPTIONS;
3408     *enabled = This->safeopt;
3409
3410     return S_OK;
3411 }
3412
3413 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3414         DWORD mask, DWORD enabled)
3415 {
3416     domdoc *This = impl_from_IObjectSafety(iface);
3417     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3418
3419     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3420         return E_FAIL;
3421
3422     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3423     return S_OK;
3424 }
3425
3426 #undef SAFETY_SUPPORTED_OPTIONS
3427
3428 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3429     domdoc_Safety_QueryInterface,
3430     domdoc_Safety_AddRef,
3431     domdoc_Safety_Release,
3432     domdoc_Safety_GetInterfaceSafetyOptions,
3433     domdoc_Safety_SetInterfaceSafetyOptions
3434 };
3435
3436 static const tid_t domdoc_iface_tids[] = {
3437     IXMLDOMNode_tid,
3438     IXMLDOMDocument_tid,
3439     IXMLDOMDocument2_tid,
3440     0
3441 };
3442 static dispex_static_data_t domdoc_dispex = {
3443     NULL,
3444     IXMLDOMDocument2_tid,
3445     NULL,
3446     domdoc_iface_tids
3447 };
3448
3449 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3450 {
3451     domdoc *doc;
3452
3453     doc = heap_alloc( sizeof (*doc) );
3454     if( !doc )
3455         return E_OUTOFMEMORY;
3456
3457     doc->lpVtbl = &domdoc_vtbl;
3458     doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3459     doc->lpvtblIObjectWithSite = &domdocObjectSite;
3460     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3461     doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3462     doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3463     doc->ref = 1;
3464     doc->async = VARIANT_TRUE;
3465     doc->validating = 0;
3466     doc->resolving = 0;
3467     doc->properties = properties_from_xmlDocPtr(xmldoc);
3468     doc->error = S_OK;
3469     doc->stream = NULL;
3470     doc->site = NULL;
3471     doc->safeopt = 0;
3472     doc->bsc = NULL;
3473     doc->cp_list = NULL;
3474     memset(doc->events, 0, sizeof(doc->events));
3475
3476     /* events connection points */
3477     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3478     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3479     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3480
3481     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3482
3483     *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3484
3485     TRACE("returning iface %p\n", *document);
3486     return S_OK;
3487 }
3488
3489 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3490 {
3491     xmlDocPtr xmldoc;
3492     HRESULT hr;
3493
3494     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3495
3496     xmldoc = xmlNewDoc(NULL);
3497     if(!xmldoc)
3498         return E_OUTOFMEMORY;
3499
3500     xmldoc->_private = create_priv();
3501     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3502
3503     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3504     if(FAILED(hr))
3505     {
3506         free_properties(properties_from_xmlDocPtr(xmldoc));
3507         heap_free(xmldoc->_private);
3508         xmlFreeDoc(xmldoc);
3509         return hr;
3510     }
3511
3512     return hr;
3513 }
3514
3515 IUnknown* create_domdoc( xmlNodePtr document )
3516 {
3517     void* pObj = NULL;
3518     HRESULT hr;
3519
3520     TRACE("(%p)\n", document);
3521
3522     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3523     if (FAILED(hr))
3524         return NULL;
3525
3526     return pObj;
3527 }
3528
3529 #else
3530
3531 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3532 {
3533     MESSAGE("This program tried to use a DOMDocument object, but\n"
3534             "libxml2 support was not present at compile time.\n");
3535     return E_NOTIMPL;
3536 }
3537
3538 #endif