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