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