msxml3: Internally call methods with interface macros.
[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)->(v%d)\n", This, V_VT(&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 x%d %p)\n", This, newChild, V_VT(&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 %p)\n", This, 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(
2507     IXMLDOMDocument3 *iface,
2508     VARIANT onDataAvailableSink )
2509 {
2510     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2511     FIXME("%p\n", This);
2512     return E_NOTIMPL;
2513 }
2514
2515 static HRESULT WINAPI domdoc_put_onTransformNode(
2516     IXMLDOMDocument3 *iface,
2517     VARIANT onTransformNodeSink )
2518 {
2519     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2520     FIXME("%p\n", This);
2521     return E_NOTIMPL;
2522 }
2523
2524 static HRESULT WINAPI domdoc_get_namespaces(
2525     IXMLDOMDocument3* iface,
2526     IXMLDOMSchemaCollection** collection )
2527 {
2528     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529     HRESULT hr;
2530
2531     FIXME("(%p)->(%p): semi-stub\n", This, collection);
2532
2533     if (!collection) return E_POINTER;
2534
2535     if (!This->namespaces)
2536     {
2537         hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2538         if (hr != S_OK) return hr;
2539
2540         hr = cache_from_doc_ns(This->namespaces, &This->node);
2541         if (hr != S_OK)
2542             release_namespaces(This);
2543     }
2544
2545     if (This->namespaces)
2546         return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2547                    &IID_IXMLDOMSchemaCollection, (void**)collection);
2548
2549     return hr;
2550 }
2551
2552 static HRESULT WINAPI domdoc_get_schemas(
2553     IXMLDOMDocument3* iface,
2554     VARIANT* var1 )
2555 {
2556     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2557     HRESULT hr = S_FALSE;
2558     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2559
2560     TRACE("(%p)->(%p)\n", This, var1);
2561
2562     VariantInit(var1); /* Test shows we don't call VariantClear here */
2563     V_VT(var1) = VT_NULL;
2564
2565     if(cur_schema)
2566     {
2567         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2568         if(SUCCEEDED(hr))
2569             V_VT(var1) = VT_DISPATCH;
2570     }
2571     return hr;
2572 }
2573
2574 static HRESULT WINAPI domdoc_putref_schemas(
2575     IXMLDOMDocument3* iface,
2576     VARIANT var1)
2577 {
2578     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2579     HRESULT hr = E_FAIL;
2580     IXMLDOMSchemaCollection2* new_schema = NULL;
2581
2582     FIXME("(%p): semi-stub\n", This);
2583     switch(V_VT(&var1))
2584     {
2585     case VT_UNKNOWN:
2586         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2587         break;
2588
2589     case VT_DISPATCH:
2590         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2591         break;
2592
2593     case VT_NULL:
2594     case VT_EMPTY:
2595         hr = S_OK;
2596         break;
2597
2598     default:
2599         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2600     }
2601
2602     if(SUCCEEDED(hr))
2603     {
2604         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2605         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2606     }
2607
2608     return hr;
2609 }
2610
2611 static inline BOOL is_wellformed(xmlDocPtr doc)
2612 {
2613 #ifdef HAVE_XMLDOC_PROPERTIES
2614     return doc->properties & XML_DOC_WELLFORMED;
2615 #else
2616     /* Not a full check, but catches the worst violations */
2617     xmlNodePtr child;
2618     int root = 0;
2619
2620     for (child = doc->children; child != NULL; child = child->next)
2621     {
2622         switch (child->type)
2623         {
2624         case XML_ELEMENT_NODE:
2625             if (++root > 1)
2626                 return FALSE;
2627             break;
2628         case XML_TEXT_NODE:
2629         case XML_CDATA_SECTION_NODE:
2630             return FALSE;
2631             break;
2632         default:
2633             break;
2634         }
2635     }
2636
2637     return root == 1;
2638 #endif
2639 }
2640
2641 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2642 {
2643     va_list ap;
2644     va_start(ap, msg);
2645     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2646     va_end(ap);
2647 }
2648
2649 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2650 {
2651     va_list ap;
2652     va_start(ap, msg);
2653     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2654     va_end(ap);
2655 }
2656
2657 static HRESULT WINAPI domdoc_validateNode(
2658     IXMLDOMDocument3* iface,
2659     IXMLDOMNode* node,
2660     IXMLDOMParseError** err)
2661 {
2662     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2663     LONG state, err_code = 0;
2664     HRESULT hr = S_OK;
2665     int validated = 0;
2666
2667     TRACE("(%p)->(%p, %p)\n", This, node, err);
2668     IXMLDOMDocument3_get_readyState(iface, &state);
2669     if (state != READYSTATE_COMPLETE)
2670     {
2671         if (err)
2672            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2673         return E_PENDING;
2674     }
2675
2676     if (!node)
2677     {
2678         if (err)
2679             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2680         return E_POINTER;
2681     }
2682
2683     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2684     {
2685         if (err)
2686             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2687         return E_FAIL;
2688     }
2689
2690     if (!is_wellformed(get_doc(This)))
2691     {
2692         ERR("doc not well-formed\n");
2693         if (err)
2694             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2695         return S_FALSE;
2696     }
2697
2698     /* DTD validation */
2699     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2700     {
2701         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2702         vctx->error = validate_error;
2703         vctx->warning = validate_warning;
2704         ++validated;
2705
2706         if (!((node == (IXMLDOMNode*)iface)?
2707               xmlValidateDocument(vctx, get_doc(This)) :
2708               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2709         {
2710             /* TODO: get a real error code here */
2711             TRACE("DTD validation failed\n");
2712             err_code = E_XML_INVALID;
2713             hr = S_FALSE;
2714         }
2715         xmlFreeValidCtxt(vctx);
2716     }
2717
2718     /* Schema validation */
2719     if (hr == S_OK && This->properties->schemaCache != NULL)
2720     {
2721
2722         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2723         if (SUCCEEDED(hr))
2724         {
2725             ++validated;
2726             /* TODO: get a real error code here */
2727             if (hr == S_OK)
2728             {
2729                 TRACE("schema validation succeeded\n");
2730             }
2731             else
2732             {
2733                 ERR("schema validation failed\n");
2734                 err_code = E_XML_INVALID;
2735             }
2736         }
2737         else
2738         {
2739             /* not really OK, just didn't find a schema for the ns */
2740             hr = S_OK;
2741         }
2742     }
2743
2744     if (!validated)
2745     {
2746         ERR("no DTD or schema found\n");
2747         err_code = E_XML_NODTD;
2748         hr = S_FALSE;
2749     }
2750
2751     if (err)
2752         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2753
2754     return hr;
2755 }
2756
2757 static HRESULT WINAPI domdoc_validate(
2758     IXMLDOMDocument3* iface,
2759     IXMLDOMParseError** err)
2760 {
2761     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2762     TRACE("(%p)->(%p)\n", This, err);
2763     return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2764 }
2765
2766 static HRESULT WINAPI domdoc_setProperty(
2767     IXMLDOMDocument3* iface,
2768     BSTR p,
2769     VARIANT var)
2770 {
2771     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2772
2773     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2774
2775     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2776     {
2777         VARIANT varStr;
2778         HRESULT hr;
2779         BSTR bstr;
2780
2781         V_VT(&varStr) = VT_EMPTY;
2782         if (V_VT(&var) != VT_BSTR)
2783         {
2784             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2785                 return hr;
2786             bstr = V_BSTR(&varStr);
2787         }
2788         else
2789             bstr = V_BSTR(&var);
2790
2791         hr = S_OK;
2792         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2793             This->properties->XPath = TRUE;
2794         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2795             This->properties->XPath = FALSE;
2796         else
2797             hr = E_FAIL;
2798
2799         VariantClear(&varStr);
2800         return hr;
2801     }
2802     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2803     {
2804         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2805         struct list *pNsList;
2806         VARIANT varStr;
2807         HRESULT hr;
2808         BSTR bstr;
2809
2810         V_VT(&varStr) = VT_EMPTY;
2811         if (V_VT(&var) != VT_BSTR)
2812         {
2813             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2814                 return hr;
2815             bstr = V_BSTR(&varStr);
2816         }
2817         else
2818             bstr = V_BSTR(&var);
2819
2820         hr = S_OK;
2821
2822         pNsList = &(This->properties->selectNsList);
2823         clear_selectNsList(pNsList);
2824         heap_free(nsStr);
2825         nsStr = xmlchar_from_wchar(bstr);
2826
2827         TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2828
2829         This->properties->selectNsStr = nsStr;
2830         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2831         if (bstr && *bstr)
2832         {
2833             xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2834             select_ns_entry* ns_entry = NULL;
2835             xmlXPathContextPtr ctx;
2836
2837             ctx = xmlXPathNewContext(This->node.node->doc);
2838             pTokBegin = nsStr;
2839
2840             /* skip leading spaces */
2841             while (*pTokBegin == ' '  || *pTokBegin == '\n' ||
2842                    *pTokBegin == '\t' || *pTokBegin == '\r')
2843                 ++pTokBegin;
2844
2845             for (; *pTokBegin; pTokBegin = pTokEnd)
2846             {
2847                 if (ns_entry)
2848                     memset(ns_entry, 0, sizeof(select_ns_entry));
2849                 else
2850                     ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2851
2852                 while (*pTokBegin == ' ')
2853                     ++pTokBegin;
2854                 pTokEnd = pTokBegin;
2855                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2856                     ++pTokEnd;
2857
2858                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2859                 {
2860                     hr = E_FAIL;
2861                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2862                           debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2863                     continue;
2864                 }
2865
2866                 pTokBegin += 5;
2867                 if (*pTokBegin == '=')
2868                 {
2869                     /*valid for XSLPattern?*/
2870                     FIXME("Setting default xmlns not supported - skipping.\n");
2871                     continue;
2872                 }
2873                 else if (*pTokBegin == ':')
2874                 {
2875                     ns_entry->prefix = ++pTokBegin;
2876                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2877                         ;
2878
2879                     if (pTokInner == pTokEnd)
2880                     {
2881                         hr = E_FAIL;
2882                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2883                               debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2884                         continue;
2885                     }
2886
2887                     ns_entry->prefix_end = *pTokInner;
2888                     *pTokInner = 0;
2889                     ++pTokInner;
2890
2891                     if (pTokEnd-pTokInner > 1 &&
2892                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2893                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2894                     {
2895                         ns_entry->href = ++pTokInner;
2896                         ns_entry->href_end = *(pTokEnd-1);
2897                         *(pTokEnd-1) = 0;
2898                         list_add_tail(pNsList, &ns_entry->entry);
2899                         /*let libxml figure out if they're valid from here ;)*/
2900                         if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2901                         {
2902                             hr = E_FAIL;
2903                         }
2904                         ns_entry = NULL;
2905                         continue;
2906                     }
2907                     else
2908                     {
2909                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2910                               debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2911                         list_add_tail(pNsList, &ns_entry->entry);
2912
2913                         ns_entry = NULL;
2914                         hr = E_FAIL;
2915                         continue;
2916                     }
2917                 }
2918                 else
2919                 {
2920                     hr = E_FAIL;
2921                     continue;
2922                 }
2923             }
2924             heap_free(ns_entry);
2925             xmlXPathFreeContext(ctx);
2926         }
2927
2928         VariantClear(&varStr);
2929         return hr;
2930     }
2931     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2932              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2933              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2934     {
2935         /* Ignore */
2936         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2937         return S_OK;
2938     }
2939
2940     FIXME("Unknown property %s\n", debugstr_w(p));
2941     return E_FAIL;
2942 }
2943
2944 static HRESULT WINAPI domdoc_getProperty(
2945     IXMLDOMDocument3* iface,
2946     BSTR p,
2947     VARIANT* var)
2948 {
2949     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2950
2951     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2952
2953     if (!var)
2954         return E_INVALIDARG;
2955
2956     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2957     {
2958         V_VT(var) = VT_BSTR;
2959         V_BSTR(var) = This->properties->XPath ?
2960                       SysAllocString(PropValueXPathW) :
2961                       SysAllocString(PropValueXSLPatternW);
2962         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2963     }
2964     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2965     {
2966         int lenA, lenW;
2967         BSTR rebuiltStr, cur;
2968         const xmlChar *nsStr;
2969         struct list *pNsList;
2970         select_ns_entry* pNsEntry;
2971
2972         V_VT(var) = VT_BSTR;
2973         nsStr = This->properties->selectNsStr;
2974         pNsList = &This->properties->selectNsList;
2975         lenA = This->properties->selectNsStr_len;
2976         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2977         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2978         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2979         cur = rebuiltStr;
2980         /* this is fine because all of the chars that end tokens are ASCII*/
2981         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2982         {
2983             while (*cur != 0) ++cur;
2984             if (pNsEntry->prefix_end)
2985             {
2986                 *cur = pNsEntry->prefix_end;
2987                 while (*cur != 0) ++cur;
2988             }
2989
2990             if (pNsEntry->href_end)
2991             {
2992                 *cur = pNsEntry->href_end;
2993             }
2994         }
2995         V_BSTR(var) = SysAllocString(rebuiltStr);
2996         heap_free(rebuiltStr);
2997         return S_OK;
2998     }
2999
3000     FIXME("Unknown property %s\n", debugstr_w(p));
3001     return E_FAIL;
3002 }
3003
3004 static HRESULT WINAPI domdoc_importNode(
3005     IXMLDOMDocument3* iface,
3006     IXMLDOMNode* node,
3007     VARIANT_BOOL deep,
3008     IXMLDOMNode** clone)
3009 {
3010     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3011     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3012     return E_NOTIMPL;
3013 }
3014
3015 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3016 {
3017     domdoc_QueryInterface,
3018     domdoc_AddRef,
3019     domdoc_Release,
3020     domdoc_GetTypeInfoCount,
3021     domdoc_GetTypeInfo,
3022     domdoc_GetIDsOfNames,
3023     domdoc_Invoke,
3024     domdoc_get_nodeName,
3025     domdoc_get_nodeValue,
3026     domdoc_put_nodeValue,
3027     domdoc_get_nodeType,
3028     domdoc_get_parentNode,
3029     domdoc_get_childNodes,
3030     domdoc_get_firstChild,
3031     domdoc_get_lastChild,
3032     domdoc_get_previousSibling,
3033     domdoc_get_nextSibling,
3034     domdoc_get_attributes,
3035     domdoc_insertBefore,
3036     domdoc_replaceChild,
3037     domdoc_removeChild,
3038     domdoc_appendChild,
3039     domdoc_hasChildNodes,
3040     domdoc_get_ownerDocument,
3041     domdoc_cloneNode,
3042     domdoc_get_nodeTypeString,
3043     domdoc_get_text,
3044     domdoc_put_text,
3045     domdoc_get_specified,
3046     domdoc_get_definition,
3047     domdoc_get_nodeTypedValue,
3048     domdoc_put_nodeTypedValue,
3049     domdoc_get_dataType,
3050     domdoc_put_dataType,
3051     domdoc_get_xml,
3052     domdoc_transformNode,
3053     domdoc_selectNodes,
3054     domdoc_selectSingleNode,
3055     domdoc_get_parsed,
3056     domdoc_get_namespaceURI,
3057     domdoc_get_prefix,
3058     domdoc_get_baseName,
3059     domdoc_transformNodeToObject,
3060     domdoc_get_doctype,
3061     domdoc_get_implementation,
3062     domdoc_get_documentElement,
3063     domdoc_put_documentElement,
3064     domdoc_createElement,
3065     domdoc_createDocumentFragment,
3066     domdoc_createTextNode,
3067     domdoc_createComment,
3068     domdoc_createCDATASection,
3069     domdoc_createProcessingInstruction,
3070     domdoc_createAttribute,
3071     domdoc_createEntityReference,
3072     domdoc_getElementsByTagName,
3073     domdoc_createNode,
3074     domdoc_nodeFromID,
3075     domdoc_load,
3076     domdoc_get_readyState,
3077     domdoc_get_parseError,
3078     domdoc_get_url,
3079     domdoc_get_async,
3080     domdoc_put_async,
3081     domdoc_abort,
3082     domdoc_loadXML,
3083     domdoc_save,
3084     domdoc_get_validateOnParse,
3085     domdoc_put_validateOnParse,
3086     domdoc_get_resolveExternals,
3087     domdoc_put_resolveExternals,
3088     domdoc_get_preserveWhiteSpace,
3089     domdoc_put_preserveWhiteSpace,
3090     domdoc_put_onreadystatechange,
3091     domdoc_put_onDataAvailable,
3092     domdoc_put_onTransformNode,
3093     domdoc_get_namespaces,
3094     domdoc_get_schemas,
3095     domdoc_putref_schemas,
3096     domdoc_validate,
3097     domdoc_setProperty,
3098     domdoc_getProperty,
3099     domdoc_validateNode,
3100     domdoc_importNode
3101 };
3102
3103 /* IConnectionPointContainer */
3104 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3105                                                               REFIID riid, void **ppv)
3106 {
3107     domdoc *This = impl_from_IConnectionPointContainer(iface);
3108     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3109 }
3110
3111 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3112 {
3113     domdoc *This = impl_from_IConnectionPointContainer(iface);
3114     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3115 }
3116
3117 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3118 {
3119     domdoc *This = impl_from_IConnectionPointContainer(iface);
3120     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3121 }
3122
3123 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3124         IEnumConnectionPoints **ppEnum)
3125 {
3126     domdoc *This = impl_from_IConnectionPointContainer(iface);
3127     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3128     return E_NOTIMPL;
3129 }
3130
3131 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3132         REFIID riid, IConnectionPoint **cp)
3133 {
3134     domdoc *This = impl_from_IConnectionPointContainer(iface);
3135     ConnectionPoint *iter;
3136
3137     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3138
3139     *cp = NULL;
3140
3141     for(iter = This->cp_list; iter; iter = iter->next)
3142     {
3143         if (IsEqualGUID(iter->iid, riid))
3144             *cp = &iter->IConnectionPoint_iface;
3145     }
3146
3147     if (*cp)
3148     {
3149         IConnectionPoint_AddRef(*cp);
3150         return S_OK;
3151     }
3152
3153     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3154     return CONNECT_E_NOCONNECTION;
3155
3156 }
3157
3158 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3159 {
3160     ConnectionPointContainer_QueryInterface,
3161     ConnectionPointContainer_AddRef,
3162     ConnectionPointContainer_Release,
3163     ConnectionPointContainer_EnumConnectionPoints,
3164     ConnectionPointContainer_FindConnectionPoint
3165 };
3166
3167 /* IConnectionPoint */
3168 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3169                                                      REFIID riid, void **ppv)
3170 {
3171     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3172
3173     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3174
3175     *ppv = NULL;
3176
3177     if (IsEqualGUID(&IID_IUnknown, riid) ||
3178         IsEqualGUID(&IID_IConnectionPoint, riid))
3179     {
3180         *ppv = iface;
3181     }
3182
3183     if (*ppv)
3184     {
3185         IConnectionPoint_AddRef(iface);
3186         return S_OK;
3187     }
3188
3189     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3190     return E_NOINTERFACE;
3191 }
3192
3193 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3194 {
3195     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3196     return IConnectionPointContainer_AddRef(This->container);
3197 }
3198
3199 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3200 {
3201     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3202     return IConnectionPointContainer_Release(This->container);
3203 }
3204
3205 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3206 {
3207     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3208
3209     TRACE("(%p)->(%p)\n", This, iid);
3210
3211     if (!iid) return E_POINTER;
3212
3213     *iid = *This->iid;
3214     return S_OK;
3215 }
3216
3217 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3218         IConnectionPointContainer **container)
3219 {
3220     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3221
3222     TRACE("(%p)->(%p)\n", This, container);
3223
3224     if (!container) return E_POINTER;
3225
3226     *container = This->container;
3227     IConnectionPointContainer_AddRef(*container);
3228     return S_OK;
3229 }
3230
3231 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3232                                              DWORD *pdwCookie)
3233 {
3234     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3235     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3236     return E_NOTIMPL;
3237 }
3238
3239 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3240 {
3241     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3242
3243     TRACE("(%p)->(%d)\n", This, cookie);
3244
3245     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3246         return CONNECT_E_NOCONNECTION;
3247
3248     IUnknown_Release(This->sinks[cookie-1].unk);
3249     This->sinks[cookie-1].unk = NULL;
3250
3251     return S_OK;
3252 }
3253
3254 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3255                                                       IEnumConnections **ppEnum)
3256 {
3257     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3258     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3259     return E_NOTIMPL;
3260 }
3261
3262 static const IConnectionPointVtbl ConnectionPointVtbl =
3263 {
3264     ConnectionPoint_QueryInterface,
3265     ConnectionPoint_AddRef,
3266     ConnectionPoint_Release,
3267     ConnectionPoint_GetConnectionInterface,
3268     ConnectionPoint_GetConnectionPointContainer,
3269     ConnectionPoint_Advise,
3270     ConnectionPoint_Unadvise,
3271     ConnectionPoint_EnumConnections
3272 };
3273
3274 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3275 {
3276     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3277     cp->doc = doc;
3278     cp->iid = riid;
3279     cp->sinks = NULL;
3280     cp->sinks_size = 0;
3281
3282     cp->next = doc->cp_list;
3283     doc->cp_list = cp;
3284
3285     cp->container = &doc->IConnectionPointContainer_iface;
3286 }
3287
3288 /* domdoc implementation of IObjectWithSite */
3289 static HRESULT WINAPI
3290 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3291 {
3292     domdoc *This = impl_from_IObjectWithSite(iface);
3293     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3294 }
3295
3296 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3297 {
3298     domdoc *This = impl_from_IObjectWithSite(iface);
3299     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3300 }
3301
3302 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3303 {
3304     domdoc *This = impl_from_IObjectWithSite(iface);
3305     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3306 }
3307
3308 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3309 {
3310     domdoc *This = impl_from_IObjectWithSite(iface);
3311
3312     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3313
3314     if ( !This->site )
3315         return E_FAIL;
3316
3317     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3318 }
3319
3320 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3321 {
3322     domdoc *This = impl_from_IObjectWithSite(iface);
3323
3324     TRACE("(%p)->(%p)\n", iface, punk);
3325
3326     if(!punk)
3327     {
3328         if(This->site)
3329         {
3330             IUnknown_Release( This->site );
3331             This->site = NULL;
3332         }
3333
3334         return S_OK;
3335     }
3336
3337     IUnknown_AddRef( punk );
3338
3339     if(This->site)
3340         IUnknown_Release( This->site );
3341
3342     This->site = punk;
3343
3344     return S_OK;
3345 }
3346
3347 static const IObjectWithSiteVtbl domdocObjectSite =
3348 {
3349     domdoc_ObjectWithSite_QueryInterface,
3350     domdoc_ObjectWithSite_AddRef,
3351     domdoc_ObjectWithSite_Release,
3352     domdoc_ObjectWithSite_SetSite,
3353     domdoc_ObjectWithSite_GetSite
3354 };
3355
3356 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3357 {
3358     domdoc *This = impl_from_IObjectSafety(iface);
3359     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3360 }
3361
3362 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3363 {
3364     domdoc *This = impl_from_IObjectSafety(iface);
3365     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3366 }
3367
3368 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3369 {
3370     domdoc *This = impl_from_IObjectSafety(iface);
3371     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3372 }
3373
3374 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3375
3376 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3377         DWORD *supported, DWORD *enabled)
3378 {
3379     domdoc *This = impl_from_IObjectSafety(iface);
3380
3381     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3382
3383     if(!supported || !enabled) return E_POINTER;
3384
3385     *supported = SAFETY_SUPPORTED_OPTIONS;
3386     *enabled = This->safeopt;
3387
3388     return S_OK;
3389 }
3390
3391 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3392         DWORD mask, DWORD enabled)
3393 {
3394     domdoc *This = impl_from_IObjectSafety(iface);
3395     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3396
3397     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3398         return E_FAIL;
3399
3400     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3401
3402     return S_OK;
3403 }
3404
3405 #undef SAFETY_SUPPORTED_OPTIONS
3406
3407 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3408     domdoc_Safety_QueryInterface,
3409     domdoc_Safety_AddRef,
3410     domdoc_Safety_Release,
3411     domdoc_Safety_GetInterfaceSafetyOptions,
3412     domdoc_Safety_SetInterfaceSafetyOptions
3413 };
3414
3415 static const tid_t domdoc_iface_tids[] = {
3416     IXMLDOMDocument3_tid,
3417     0
3418 };
3419
3420 static dispex_static_data_t domdoc_dispex = {
3421     NULL,
3422     IXMLDOMDocument3_tid,
3423     NULL,
3424     domdoc_iface_tids
3425 };
3426
3427 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3428 {
3429     domdoc *doc;
3430
3431     doc = heap_alloc( sizeof (*doc) );
3432     if( !doc )
3433         return E_OUTOFMEMORY;
3434
3435     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3436     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3437     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3438     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3439     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3440     doc->ref = 1;
3441     doc->async = VARIANT_TRUE;
3442     doc->validating = 0;
3443     doc->resolving = 0;
3444     doc->properties = properties_from_xmlDocPtr(xmldoc);
3445     doc->error = S_OK;
3446     doc->stream = NULL;
3447     doc->site = NULL;
3448     doc->safeopt = 0;
3449     doc->bsc = NULL;
3450     doc->cp_list = NULL;
3451     doc->namespaces = NULL;
3452     memset(doc->events, 0, sizeof(doc->events));
3453
3454     /* events connection points */
3455     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3456     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3457     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3458
3459     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3460             &domdoc_dispex);
3461
3462     *document = &doc->IXMLDOMDocument3_iface;
3463
3464     TRACE("returning iface %p\n", *document);
3465     return S_OK;
3466 }
3467
3468 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3469 {
3470     xmlDocPtr xmldoc;
3471     HRESULT hr;
3472
3473     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3474
3475     xmldoc = xmlNewDoc(NULL);
3476     if(!xmldoc)
3477         return E_OUTOFMEMORY;
3478
3479     xmldoc_init(xmldoc, version);
3480
3481     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3482     if(FAILED(hr))
3483     {
3484         free_properties(properties_from_xmlDocPtr(xmldoc));
3485         heap_free(xmldoc->_private);
3486         xmlFreeDoc(xmldoc);
3487         return hr;
3488     }
3489
3490     return hr;
3491 }
3492
3493 IUnknown* create_domdoc( xmlNodePtr document )
3494 {
3495     void* pObj = NULL;
3496     HRESULT hr;
3497
3498     TRACE("(%p)\n", document);
3499
3500     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3501     if (FAILED(hr))
3502         return NULL;
3503
3504     return pObj;
3505 }
3506
3507 #else
3508
3509 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3510 {
3511     MESSAGE("This program tried to use a DOMDocument object, but\n"
3512             "libxml2 support was not present at compile time.\n");
3513     return E_NOTIMPL;
3514 }
3515
3516 #endif