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