gdi.exe16: Constify a variable.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2010 Adam Martinson for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include "config.h"
26
27 #include <stdarg.h>
28 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "ole2.h"
34 #include "msxml6.h"
35 #include "wininet.h"
36 #include "winreg.h"
37 #include "shlwapi.h"
38 #include "ocidl.h"
39 #include "objsafe.h"
40 #include "dispex.h"
41
42 #include "wine/debug.h"
43 #include "wine/list.h"
44
45 #include "msxml_private.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
48
49 #ifdef HAVE_LIBXML2
50
51 #include <libxml/xpathInternals.h>
52 #include <libxml/xmlsave.h>
53 #include <libxml/SAX2.h>
54
55 /* not defined in older versions */
56 #define XML_SAVE_FORMAT     1
57 #define XML_SAVE_NO_DECL    2
58 #define XML_SAVE_NO_EMPTY   4
59 #define XML_SAVE_NO_XHTML   8
60 #define XML_SAVE_XHTML     16
61 #define XML_SAVE_AS_XML    32
62 #define XML_SAVE_AS_HTML   64
63
64 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
65 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
66 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
67 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
68 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
69
70 /* Data used by domdoc_getProperty()/domdoc_setProperty().
71  * We need to preserve this when reloading a document,
72  * and also need access to it from the libxml backend. */
73 typedef struct _domdoc_properties {
74     struct list selectNsList;
75     xmlChar const* selectNsStr;
76     LONG selectNsStr_len;
77     BOOL XPath;
78 } domdoc_properties;
79
80 typedef struct _domdoc
81 {
82     xmlnode node;
83     const struct IXMLDOMDocument3Vtbl *lpVtbl;
84     const struct IPersistStreamInitVtbl   *lpvtblIPersistStreamInit;
85     const struct IObjectWithSiteVtbl  *lpvtblIObjectWithSite;
86     const struct IObjectSafetyVtbl    *lpvtblIObjectSafety;
87     const struct ISupportErrorInfoVtbl *lpvtblISupportErrorInfo;
88     LONG ref;
89     VARIANT_BOOL async;
90     VARIANT_BOOL validating;
91     VARIANT_BOOL resolving;
92     VARIANT_BOOL preserving;
93     domdoc_properties* properties;
94     IXMLDOMSchemaCollection *schema;
95     bsc_t *bsc;
96     HRESULT error;
97
98     /* IPersistStream */
99     IStream *stream;
100
101     /* IObjectWithSite*/
102     IUnknown *site;
103
104     /* IObjectSafety */
105     DWORD safeopt;
106 } domdoc;
107
108 /*
109   In native windows, the whole lifetime management of XMLDOMNodes is
110   managed automatically using reference counts. Wine emulates that by
111   maintaining a reference count to the document that is increased for
112   each IXMLDOMNode pointer passed out for this document. If all these
113   pointers are gone, the document is unreachable and gets freed, that
114   is, all nodes in the tree of the document get freed.
115
116   You are able to create nodes that are associated to a document (in
117   fact, in msxml's XMLDOM model, all nodes are associated to a document),
118   but not in the tree of that document, for example using the createFoo
119   functions from IXMLDOMDocument. These nodes do not get cleaned up
120   by libxml, so we have to do it ourselves.
121
122   To catch these nodes, a list of "orphan nodes" is introduced.
123   It contains pointers to all roots of node trees that are
124   associated with the document without being part of the document
125   tree. All nodes with parent==NULL (except for the document root nodes)
126   should be in the orphan node list of their document. All orphan nodes
127   get freed together with the document itself.
128  */
129
130 typedef struct _xmldoc_priv {
131     LONG refs;
132     struct list orphans;
133     domdoc_properties* properties;
134 } xmldoc_priv;
135
136 typedef struct _orphan_entry {
137     struct list entry;
138     xmlNode * node;
139 } orphan_entry;
140
141 typedef struct _select_ns_entry {
142     struct list entry;
143     xmlChar const* prefix;
144     xmlChar prefix_end;
145     xmlChar const* href;
146     xmlChar href_end;
147 } select_ns_entry;
148
149 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
150 {
151     return doc->_private;
152 }
153
154 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
155 {
156     return priv_from_xmlDocPtr(doc)->properties;
157 }
158
159 static inline BOOL is_xpathmode(const xmlDocPtr doc)
160 {
161     return properties_from_xmlDocPtr(doc)->XPath;
162 }
163
164 int registerNamespaces(xmlXPathContextPtr ctxt)
165 {
166     int n = 0;
167     const select_ns_entry* ns = NULL;
168     const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
169
170     TRACE("(%p)\n", ctxt);
171
172     LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
173     {
174         xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
175         ++n;
176     }
177
178     return n;
179 }
180
181 static inline void clear_selectNsList(struct list* pNsList)
182 {
183     select_ns_entry *ns, *ns2;
184     LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
185     {
186         heap_free( ns );
187     }
188     list_init(pNsList);
189 }
190
191 static xmldoc_priv * create_priv(void)
192 {
193     xmldoc_priv *priv;
194     priv = heap_alloc( sizeof (*priv) );
195
196     if (priv)
197     {
198         priv->refs = 0;
199         list_init( &priv->orphans );
200         priv->properties = NULL;
201     }
202
203     return priv;
204 }
205
206 static domdoc_properties * create_properties(const GUID *clsid)
207 {
208     domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
209
210     list_init( &properties->selectNsList );
211     properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
212     properties->selectNsStr_len = 0;
213     properties->XPath = FALSE;
214
215     /* properties that are dependent on object versions */
216     if (IsEqualCLSID( clsid, &CLSID_DOMDocument40 ) ||
217         IsEqualCLSID( clsid, &CLSID_DOMDocument60 ))
218     {
219         properties->XPath = TRUE;
220     }
221
222     return properties;
223 }
224
225 static domdoc_properties* copy_properties(domdoc_properties const* properties)
226 {
227     domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
228     select_ns_entry const* ns = NULL;
229     select_ns_entry* new_ns = NULL;
230     int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
231     ptrdiff_t offset;
232
233     if (pcopy)
234     {
235         pcopy->XPath = properties->XPath;
236         pcopy->selectNsStr_len = properties->selectNsStr_len;
237         list_init( &pcopy->selectNsList );
238         pcopy->selectNsStr = heap_alloc(len);
239         memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
240         offset = pcopy->selectNsStr - properties->selectNsStr;
241
242         LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
243         {
244             new_ns = heap_alloc(sizeof(select_ns_entry));
245             memcpy(new_ns, ns, sizeof(select_ns_entry));
246             new_ns->href += offset;
247             new_ns->prefix += offset;
248             list_add_tail(&pcopy->selectNsList, &new_ns->entry);
249         }
250
251     }
252
253     return pcopy;
254 }
255
256 static void free_properties(domdoc_properties* properties)
257 {
258     if (properties)
259     {
260         clear_selectNsList(&properties->selectNsList);
261         heap_free((xmlChar*)properties->selectNsStr);
262         heap_free(properties);
263     }
264 }
265
266 /* links a "<?xml" node as a first child */
267 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
268 {
269     assert(doc != NULL);
270     if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
271 }
272
273 /* unlinks a first "<?xml" child if it was created */
274 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
275 {
276     xmlNodePtr node;
277
278     assert(doc != NULL);
279
280     if (doc->standalone != -1)
281     {
282         node = doc->children;
283         xmlUnlinkNode( node );
284     }
285     else
286         node = NULL;
287
288     return node;
289 }
290
291 static inline BOOL strn_isspace(xmlChar const* str, int len)
292 {
293     for (; str && len > 0 && *str; ++str, --len)
294         if (!isspace(*str))
295             break;
296
297     return len == 0;
298 }
299
300 static void sax_characters(void *ctx, const xmlChar *ch, int len)
301 {
302     xmlParserCtxtPtr pctx;
303     domdoc const* This;
304
305     pctx = (xmlParserCtxtPtr) ctx;
306     This = (domdoc const*) pctx->_private;
307
308     if (!This->preserving)
309     {
310         xmlChar* ws = xmlGetNsProp(pctx->node, BAD_CAST "space", XML_XML_NAMESPACE);
311         if ((!ws || xmlStrcmp(ws, BAD_CAST "preserve") != 0) &&
312             strn_isspace(ch, len))
313         {
314             xmlFree(ws);
315             return;
316         }
317         xmlFree(ws);
318     }
319
320     xmlSAX2Characters(ctx, ch, len);
321 }
322
323 static xmlDocPtr doparse(domdoc* This, char *ptr, int len)
324 {
325     xmlDocPtr doc;
326     static xmlSAXHandler sax_handler = {
327         xmlSAX2InternalSubset,          /* internalSubset */
328         xmlSAX2IsStandalone,            /* isStandalone */
329         xmlSAX2HasInternalSubset,       /* hasInternalSubset */
330         xmlSAX2HasExternalSubset,       /* hasExternalSubset */
331         xmlSAX2ResolveEntity,           /* resolveEntity */
332         xmlSAX2GetEntity,               /* getEntity */
333         xmlSAX2EntityDecl,              /* entityDecl */
334         xmlSAX2NotationDecl,            /* notationDecl */
335         xmlSAX2AttributeDecl,           /* attributeDecl */
336         xmlSAX2ElementDecl,             /* elementDecl */
337         xmlSAX2UnparsedEntityDecl,      /* unparsedEntityDecl */
338         xmlSAX2SetDocumentLocator,      /* setDocumentLocator */
339         xmlSAX2StartDocument,           /* startDocument */
340         xmlSAX2EndDocument,             /* endDocument */
341         xmlSAX2StartElement,            /* startElement */
342         xmlSAX2EndElement,              /* endElement */
343         xmlSAX2Reference,               /* reference */
344         sax_characters,                 /* characters */
345         sax_characters,                 /* ignorableWhitespace */
346         xmlSAX2ProcessingInstruction,   /* processingInstruction */
347         xmlSAX2Comment,                 /* comment */
348         NULL,                           /* TODO: warning */
349         NULL,                           /* TODO: error */
350         NULL,                           /* TODO: fatalError */
351         xmlSAX2GetParameterEntity,      /* getParameterEntity */
352         xmlSAX2CDataBlock,              /* cdataBlock */
353         xmlSAX2ExternalSubset,          /* externalSubset */
354         0,                              /* initialized */
355         NULL,                           /* _private */
356         xmlSAX2StartElementNs,          /* startElementNs */
357         xmlSAX2EndElementNs,            /* endElementNs */
358         NULL                            /* TODO: serror */
359     };
360
361     doc = xmlSAXParseMemoryWithData(&sax_handler, ptr, len, 0, This);
362
363     /* TODO: put this in one of the SAX callbacks */
364     /* create first child as a <?xml...?> */
365     if (doc && doc->standalone != -1)
366     {
367         xmlNodePtr node;
368         char buff[30];
369         xmlChar *xmlbuff = (xmlChar*)buff;
370
371         node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
372
373         /* version attribute can't be omitted */
374         sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
375         xmlNodeAddContent( node, xmlbuff );
376
377         if (doc->encoding)
378         {
379             sprintf(buff, " encoding=\"%s\"", doc->encoding);
380             xmlNodeAddContent( node, xmlbuff );
381         }
382
383         if (doc->standalone != -2)
384         {
385             sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
386             xmlNodeAddContent( node, xmlbuff );
387         }
388
389         xmldoc_link_xmldecl( doc, node );
390     }
391
392     return doc;
393 }
394
395 LONG xmldoc_add_ref(xmlDocPtr doc)
396 {
397     LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
398     TRACE("(%p)->(%d)\n", doc, ref);
399     return ref;
400 }
401
402 LONG xmldoc_release(xmlDocPtr doc)
403 {
404     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
405     LONG ref = InterlockedDecrement(&priv->refs);
406     TRACE("(%p)->(%d)\n", doc, ref);
407     if(ref == 0)
408     {
409         orphan_entry *orphan, *orphan2;
410         TRACE("freeing docptr %p\n", doc);
411
412         LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
413         {
414             xmlFreeNode( orphan->node );
415             heap_free( orphan );
416         }
417         free_properties(priv->properties);
418         heap_free(doc->_private);
419
420         xmlFreeDoc(doc);
421     }
422
423     return ref;
424 }
425
426 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
427 {
428     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
429     orphan_entry *entry;
430
431     entry = heap_alloc( sizeof (*entry) );
432     if(!entry)
433         return E_OUTOFMEMORY;
434
435     entry->node = node;
436     list_add_head( &priv->orphans, &entry->entry );
437     return S_OK;
438 }
439
440 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
441 {
442     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
443     orphan_entry *entry, *entry2;
444
445     LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
446     {
447         if( entry->node == node )
448         {
449             list_remove( &entry->entry );
450             heap_free( entry );
451             return S_OK;
452         }
453     }
454
455     return S_FALSE;
456 }
457
458 static inline xmlDocPtr get_doc( domdoc *This )
459 {
460     return (xmlDocPtr)This->node.node;
461 }
462
463 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
464 {
465     if(This->node.node)
466     {
467         priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
468         if (xmldoc_release(get_doc(This)) != 0)
469             priv_from_xmlDocPtr(get_doc(This))->properties =
470                 copy_properties(This->properties);
471     }
472
473     This->node.node = (xmlNodePtr) xml;
474
475     if(This->node.node)
476     {
477         xmldoc_add_ref(get_doc(This));
478         priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
479     }
480
481     return S_OK;
482 }
483
484 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
485 {
486     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
487 }
488
489 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
490 {
491     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIPersistStreamInit));
492 }
493
494 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
495 {
496     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectWithSite));
497 }
498
499 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
500 {
501     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectSafety));
502 }
503
504 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
505 {
506     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblISupportErrorInfo));
507 }
508
509 /************************************************************************
510  * domdoc implementation of IPersistStream.
511  */
512 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
513     IPersistStreamInit *iface, REFIID riid, void **ppvObj)
514 {
515     domdoc *this = impl_from_IPersistStreamInit(iface);
516     return IXMLDOMDocument2_QueryInterface((IXMLDOMDocument2 *)this, riid, ppvObj);
517 }
518
519 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
520     IPersistStreamInit *iface)
521 {
522     domdoc *this = impl_from_IPersistStreamInit(iface);
523     return IXMLDOMDocument2_AddRef((IXMLDOMDocument2 *)this);
524 }
525
526 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
527     IPersistStreamInit *iface)
528 {
529     domdoc *this = impl_from_IPersistStreamInit(iface);
530     return IXMLDOMDocument2_Release((IXMLDOMDocument2 *)this);
531 }
532
533 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
534     IPersistStreamInit *iface, CLSID *classid)
535 {
536     TRACE("(%p,%p): stub!\n", iface, classid);
537
538     if(!classid)
539         return E_POINTER;
540
541     *classid = CLSID_DOMDocument2;
542
543     return S_OK;
544 }
545
546 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
547     IPersistStreamInit *iface)
548 {
549     domdoc *This = impl_from_IPersistStreamInit(iface);
550     FIXME("(%p): stub!\n", This);
551     return S_FALSE;
552 }
553
554 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
555     IPersistStreamInit *iface, LPSTREAM pStm)
556 {
557     domdoc *This = impl_from_IPersistStreamInit(iface);
558     HRESULT hr;
559     HGLOBAL hglobal;
560     DWORD read, written, len;
561     BYTE buf[4096];
562     char *ptr;
563     xmlDocPtr xmldoc = NULL;
564
565     TRACE("(%p)->(%p)\n", This, pStm);
566
567     if (!pStm)
568         return E_INVALIDARG;
569
570     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
571     if (FAILED(hr))
572         return hr;
573
574     do
575     {
576         IStream_Read(pStm, buf, sizeof(buf), &read);
577         hr = IStream_Write(This->stream, buf, read, &written);
578     } while(SUCCEEDED(hr) && written != 0 && read != 0);
579
580     if (FAILED(hr))
581     {
582         ERR("Failed to copy stream\n");
583         return hr;
584     }
585
586     hr = GetHGlobalFromStream(This->stream, &hglobal);
587     if (FAILED(hr))
588         return hr;
589
590     len = GlobalSize(hglobal);
591     ptr = GlobalLock(hglobal);
592     if (len != 0)
593         xmldoc = doparse(This, ptr, len);
594     GlobalUnlock(hglobal);
595
596     if (!xmldoc)
597     {
598         ERR("Failed to parse xml\n");
599         return E_FAIL;
600     }
601
602     xmldoc->_private = create_priv();
603
604     return attach_xmldoc(This, xmldoc);
605 }
606
607 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
608     IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
609 {
610     domdoc *This = impl_from_IPersistStreamInit(iface);
611     BSTR xmlString;
612     HRESULT hr;
613
614     TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
615
616     hr = IXMLDOMDocument3_get_xml( (IXMLDOMDocument3*)&This->lpVtbl, &xmlString );
617     if(hr == S_OK)
618     {
619         DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
620
621         hr = IStream_Write( stream, xmlString, len, NULL );
622         SysFreeString(xmlString);
623     }
624
625     TRACE("ret 0x%08x\n", hr);
626
627     return hr;
628 }
629
630 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
631     IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
632 {
633     domdoc *This = impl_from_IPersistStreamInit(iface);
634     TRACE("(%p)->(%p): stub!\n", This, pcbSize);
635     return E_NOTIMPL;
636 }
637
638 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
639     IPersistStreamInit *iface)
640 {
641     domdoc *This = impl_from_IPersistStreamInit(iface);
642     TRACE("(%p)\n", This);
643     return S_OK;
644 }
645
646 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
647 {
648     domdoc_IPersistStreamInit_QueryInterface,
649     domdoc_IPersistStreamInit_AddRef,
650     domdoc_IPersistStreamInit_Release,
651     domdoc_IPersistStreamInit_GetClassID,
652     domdoc_IPersistStreamInit_IsDirty,
653     domdoc_IPersistStreamInit_Load,
654     domdoc_IPersistStreamInit_Save,
655     domdoc_IPersistStreamInit_GetSizeMax,
656     domdoc_IPersistStreamInit_InitNew
657 };
658
659 /* ISupportErrorInfo interface */
660 static HRESULT WINAPI support_error_QueryInterface(
661     ISupportErrorInfo *iface,
662     REFIID riid, void** ppvObj )
663 {
664     domdoc *This = impl_from_ISupportErrorInfo(iface);
665     return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3 *)This, riid, ppvObj);
666 }
667
668 static ULONG WINAPI support_error_AddRef(
669     ISupportErrorInfo *iface )
670 {
671     domdoc *This = impl_from_ISupportErrorInfo(iface);
672     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
673 }
674
675 static ULONG WINAPI support_error_Release(
676     ISupportErrorInfo *iface )
677 {
678     domdoc *This = impl_from_ISupportErrorInfo(iface);
679     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
680 }
681
682 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
683     ISupportErrorInfo *iface,
684     REFIID riid )
685 {
686     FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
687     return S_FALSE;
688 }
689
690 static const struct ISupportErrorInfoVtbl support_error_vtbl =
691 {
692     support_error_QueryInterface,
693     support_error_AddRef,
694     support_error_Release,
695     support_error_InterfaceSupportsErrorInfo
696 };
697
698 /* IXMLDOMDocument2 interface */
699 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
700 {
701     domdoc *This = impl_from_IXMLDOMDocument3( iface );
702
703     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
704
705     *ppvObject = NULL;
706
707     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
708          IsEqualGUID( riid, &IID_IDispatch ) ||
709          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
710          IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
711          IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
712          IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
713     {
714         *ppvObject = iface;
715     }
716     else if (IsEqualGUID(&IID_IPersistStream, riid) ||
717              IsEqualGUID(&IID_IPersistStreamInit, riid))
718     {
719         *ppvObject = &(This->lpvtblIPersistStreamInit);
720     }
721     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
722     {
723         *ppvObject = &(This->lpvtblIObjectWithSite);
724     }
725     else if (IsEqualGUID(&IID_IObjectSafety, riid))
726     {
727         *ppvObject = &(This->lpvtblIObjectSafety);
728     }
729     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
730     {
731         *ppvObject = &This->lpvtblISupportErrorInfo;
732     }
733     else if(node_query_interface(&This->node, riid, ppvObject))
734     {
735         return *ppvObject ? S_OK : E_NOINTERFACE;
736     }
737     else if(IsEqualGUID(&IID_IRunnableObject, riid))
738     {
739         TRACE("IID_IRunnableObject not supported returning NULL\n");
740         return E_NOINTERFACE;
741     }
742     else
743     {
744         FIXME("interface %s not implemented\n", debugstr_guid(riid));
745         return E_NOINTERFACE;
746     }
747
748     IUnknown_AddRef((IUnknown*)*ppvObject);
749
750     return S_OK;
751 }
752
753
754 static ULONG WINAPI domdoc_AddRef(
755      IXMLDOMDocument3 *iface )
756 {
757     domdoc *This = impl_from_IXMLDOMDocument3( iface );
758     TRACE("%p\n", This );
759     return InterlockedIncrement( &This->ref );
760 }
761
762
763 static ULONG WINAPI domdoc_Release(
764      IXMLDOMDocument3 *iface )
765 {
766     domdoc *This = impl_from_IXMLDOMDocument3( iface );
767     LONG ref;
768
769     TRACE("%p\n", This );
770
771     ref = InterlockedDecrement( &This->ref );
772     if ( ref == 0 )
773     {
774         if(This->bsc)
775             detach_bsc(This->bsc);
776
777         if (This->site)
778             IUnknown_Release( This->site );
779         destroy_xmlnode(&This->node);
780         if(This->schema) IXMLDOMSchemaCollection_Release( This->schema );
781         if (This->stream) IStream_Release(This->stream);
782         HeapFree( GetProcessHeap(), 0, This );
783     }
784
785     return ref;
786 }
787
788 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
789 {
790     domdoc *This = impl_from_IXMLDOMDocument3( iface );
791
792     TRACE("(%p)->(%p)\n", This, pctinfo);
793
794     *pctinfo = 1;
795
796     return S_OK;
797 }
798
799 static HRESULT WINAPI domdoc_GetTypeInfo(
800     IXMLDOMDocument3 *iface,
801     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
802 {
803     domdoc *This = impl_from_IXMLDOMDocument3( iface );
804     HRESULT hr;
805
806     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
807
808     hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
809
810     return hr;
811 }
812
813 static HRESULT WINAPI domdoc_GetIDsOfNames(
814     IXMLDOMDocument3 *iface,
815     REFIID riid,
816     LPOLESTR* rgszNames,
817     UINT cNames,
818     LCID lcid,
819     DISPID* rgDispId)
820 {
821     domdoc *This = impl_from_IXMLDOMDocument3( iface );
822     ITypeInfo *typeinfo;
823     HRESULT hr;
824
825     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
826           lcid, rgDispId);
827
828     if(!rgszNames || cNames == 0 || !rgDispId)
829         return E_INVALIDARG;
830
831     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
832     if(SUCCEEDED(hr))
833     {
834         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
835         ITypeInfo_Release(typeinfo);
836     }
837
838     return hr;
839 }
840
841
842 static HRESULT WINAPI domdoc_Invoke(
843     IXMLDOMDocument3 *iface,
844     DISPID dispIdMember,
845     REFIID riid,
846     LCID lcid,
847     WORD wFlags,
848     DISPPARAMS* pDispParams,
849     VARIANT* pVarResult,
850     EXCEPINFO* pExcepInfo,
851     UINT* puArgErr)
852 {
853     domdoc *This = impl_from_IXMLDOMDocument3( iface );
854     ITypeInfo *typeinfo;
855     HRESULT hr;
856
857     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
858           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
859
860     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
861     if(SUCCEEDED(hr))
862     {
863         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
864                 pVarResult, pExcepInfo, puArgErr);
865         ITypeInfo_Release(typeinfo);
866     }
867
868     return hr;
869 }
870
871
872 static HRESULT WINAPI domdoc_get_nodeName(
873     IXMLDOMDocument3 *iface,
874     BSTR* name )
875 {
876     domdoc *This = impl_from_IXMLDOMDocument3( iface );
877
878     static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
879
880     TRACE("(%p)->(%p)\n", This, name);
881
882     return return_bstr(documentW, name);
883 }
884
885
886 static HRESULT WINAPI domdoc_get_nodeValue(
887     IXMLDOMDocument3 *iface,
888     VARIANT* value )
889 {
890     domdoc *This = impl_from_IXMLDOMDocument3( iface );
891
892     TRACE("(%p)->(%p)\n", This, value);
893
894     if(!value)
895         return E_INVALIDARG;
896
897     V_VT(value) = VT_NULL;
898     V_BSTR(value) = NULL; /* tests show that we should do this */
899     return S_FALSE;
900 }
901
902
903 static HRESULT WINAPI domdoc_put_nodeValue(
904     IXMLDOMDocument3 *iface,
905     VARIANT value)
906 {
907     domdoc *This = impl_from_IXMLDOMDocument3( iface );
908     FIXME("(%p)->(v%d)\n", This, V_VT(&value));
909     return E_FAIL;
910 }
911
912
913 static HRESULT WINAPI domdoc_get_nodeType(
914     IXMLDOMDocument3 *iface,
915     DOMNodeType* type )
916 {
917     domdoc *This = impl_from_IXMLDOMDocument3( iface );
918
919     TRACE("(%p)->(%p)\n", This, type);
920
921     *type = NODE_DOCUMENT;
922     return S_OK;
923 }
924
925
926 static HRESULT WINAPI domdoc_get_parentNode(
927     IXMLDOMDocument3 *iface,
928     IXMLDOMNode** parent )
929 {
930     domdoc *This = impl_from_IXMLDOMDocument3( iface );
931
932     TRACE("(%p)->(%p)\n", This, parent);
933
934     return node_get_parent(&This->node, parent);
935 }
936
937
938 static HRESULT WINAPI domdoc_get_childNodes(
939     IXMLDOMDocument3 *iface,
940     IXMLDOMNodeList** childList )
941 {
942     domdoc *This = impl_from_IXMLDOMDocument3( iface );
943
944     TRACE("(%p)->(%p)\n", This, childList);
945
946     return node_get_child_nodes(&This->node, childList);
947 }
948
949
950 static HRESULT WINAPI domdoc_get_firstChild(
951     IXMLDOMDocument3 *iface,
952     IXMLDOMNode** firstChild )
953 {
954     domdoc *This = impl_from_IXMLDOMDocument3( iface );
955
956     TRACE("(%p)->(%p)\n", This, firstChild);
957
958     return node_get_first_child(&This->node, firstChild);
959 }
960
961
962 static HRESULT WINAPI domdoc_get_lastChild(
963     IXMLDOMDocument3 *iface,
964     IXMLDOMNode** lastChild )
965 {
966     domdoc *This = impl_from_IXMLDOMDocument3( iface );
967
968     TRACE("(%p)->(%p)\n", This, lastChild);
969
970     return node_get_last_child(&This->node, lastChild);
971 }
972
973
974 static HRESULT WINAPI domdoc_get_previousSibling(
975     IXMLDOMDocument3 *iface,
976     IXMLDOMNode** previousSibling )
977 {
978     domdoc *This = impl_from_IXMLDOMDocument3( iface );
979
980     TRACE("(%p)->(%p)\n", This, previousSibling);
981
982     return return_null_node(previousSibling);
983 }
984
985
986 static HRESULT WINAPI domdoc_get_nextSibling(
987     IXMLDOMDocument3 *iface,
988     IXMLDOMNode** nextSibling )
989 {
990     domdoc *This = impl_from_IXMLDOMDocument3( iface );
991
992     TRACE("(%p)->(%p)\n", This, nextSibling);
993
994     return return_null_node(nextSibling);
995 }
996
997
998 static HRESULT WINAPI domdoc_get_attributes(
999     IXMLDOMDocument3 *iface,
1000     IXMLDOMNamedNodeMap** attributeMap )
1001 {
1002     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1003
1004     TRACE("(%p)->(%p)\n", This, attributeMap);
1005
1006     return return_null_ptr((void**)attributeMap);
1007 }
1008
1009
1010 static HRESULT WINAPI domdoc_insertBefore(
1011     IXMLDOMDocument3 *iface,
1012     IXMLDOMNode* newChild,
1013     VARIANT refChild,
1014     IXMLDOMNode** outNewChild )
1015 {
1016     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017
1018     TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1019
1020     return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1021 }
1022
1023
1024 static HRESULT WINAPI domdoc_replaceChild(
1025     IXMLDOMDocument3 *iface,
1026     IXMLDOMNode* newChild,
1027     IXMLDOMNode* oldChild,
1028     IXMLDOMNode** outOldChild)
1029 {
1030     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1031     return IXMLDOMNode_replaceChild( IXMLDOMNode_from_impl(&This->node), newChild, oldChild, outOldChild );
1032 }
1033
1034
1035 static HRESULT WINAPI domdoc_removeChild(
1036     IXMLDOMDocument3 *iface,
1037     IXMLDOMNode* childNode,
1038     IXMLDOMNode** oldChild)
1039 {
1040     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1041     return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), childNode, oldChild );
1042 }
1043
1044
1045 static HRESULT WINAPI domdoc_appendChild(
1046     IXMLDOMDocument3 *iface,
1047     IXMLDOMNode* newChild,
1048     IXMLDOMNode** outNewChild)
1049 {
1050     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1051     return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newChild, outNewChild );
1052 }
1053
1054
1055 static HRESULT WINAPI domdoc_hasChildNodes(
1056     IXMLDOMDocument3 *iface,
1057     VARIANT_BOOL* hasChild)
1058 {
1059     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1060     return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), hasChild );
1061 }
1062
1063
1064 static HRESULT WINAPI domdoc_get_ownerDocument(
1065     IXMLDOMDocument3 *iface,
1066     IXMLDOMDocument** DOMDocument)
1067 {
1068     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1069     return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), DOMDocument );
1070 }
1071
1072
1073 static HRESULT WINAPI domdoc_cloneNode(
1074     IXMLDOMDocument3 *iface,
1075     VARIANT_BOOL deep,
1076     IXMLDOMNode** cloneRoot)
1077 {
1078     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1079     return IXMLDOMNode_cloneNode( IXMLDOMNode_from_impl(&This->node), deep, cloneRoot );
1080 }
1081
1082
1083 static HRESULT WINAPI domdoc_get_nodeTypeString(
1084     IXMLDOMDocument3 *iface,
1085     BSTR* nodeType )
1086 {
1087     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1088     return IXMLDOMNode_get_nodeTypeString( IXMLDOMNode_from_impl(&This->node), nodeType );
1089 }
1090
1091
1092 static HRESULT WINAPI domdoc_get_text(
1093     IXMLDOMDocument3 *iface,
1094     BSTR* text )
1095 {
1096     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1097     return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), text );
1098 }
1099
1100
1101 static HRESULT WINAPI domdoc_put_text(
1102     IXMLDOMDocument3 *iface,
1103     BSTR text )
1104 {
1105     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1106     return IXMLDOMNode_put_text( IXMLDOMNode_from_impl(&This->node), text );
1107 }
1108
1109
1110 static HRESULT WINAPI domdoc_get_specified(
1111     IXMLDOMDocument3 *iface,
1112     VARIANT_BOOL* isSpecified )
1113 {
1114     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1115     return IXMLDOMNode_get_specified( IXMLDOMNode_from_impl(&This->node), isSpecified );
1116 }
1117
1118
1119 static HRESULT WINAPI domdoc_get_definition(
1120     IXMLDOMDocument3 *iface,
1121     IXMLDOMNode** definitionNode )
1122 {
1123     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1124     return IXMLDOMNode_get_definition( IXMLDOMNode_from_impl(&This->node), definitionNode );
1125 }
1126
1127
1128 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1129     IXMLDOMDocument3 *iface,
1130     VARIANT* typedValue )
1131 {
1132     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1133     return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1134 }
1135
1136 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1137     IXMLDOMDocument3 *iface,
1138     VARIANT typedValue )
1139 {
1140     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1141     return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1142 }
1143
1144
1145 static HRESULT WINAPI domdoc_get_dataType(
1146     IXMLDOMDocument3 *iface,
1147     VARIANT* dataTypeName )
1148 {
1149     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1150     return IXMLDOMNode_get_dataType( IXMLDOMNode_from_impl(&This->node), dataTypeName );
1151 }
1152
1153
1154 static HRESULT WINAPI domdoc_put_dataType(
1155     IXMLDOMDocument3 *iface,
1156     BSTR dataTypeName )
1157 {
1158     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1159     return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), dataTypeName );
1160 }
1161
1162
1163 static HRESULT WINAPI domdoc_get_xml(
1164     IXMLDOMDocument3 *iface,
1165     BSTR* xmlString )
1166 {
1167     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1168     return IXMLDOMNode_get_xml( IXMLDOMNode_from_impl(&This->node), xmlString );
1169 }
1170
1171
1172 static HRESULT WINAPI domdoc_transformNode(
1173     IXMLDOMDocument3 *iface,
1174     IXMLDOMNode* styleSheet,
1175     BSTR* xmlString )
1176 {
1177     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1178     return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), styleSheet, xmlString );
1179 }
1180
1181
1182 static HRESULT WINAPI domdoc_selectNodes(
1183     IXMLDOMDocument3 *iface,
1184     BSTR queryString,
1185     IXMLDOMNodeList** resultList )
1186 {
1187     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1188     return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), queryString, resultList );
1189 }
1190
1191
1192 static HRESULT WINAPI domdoc_selectSingleNode(
1193     IXMLDOMDocument3 *iface,
1194     BSTR queryString,
1195     IXMLDOMNode** resultNode )
1196 {
1197     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1198     return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), queryString, resultNode );
1199 }
1200
1201
1202 static HRESULT WINAPI domdoc_get_parsed(
1203     IXMLDOMDocument3 *iface,
1204     VARIANT_BOOL* isParsed )
1205 {
1206     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1207     return IXMLDOMNode_get_parsed( IXMLDOMNode_from_impl(&This->node), isParsed );
1208 }
1209
1210
1211 static HRESULT WINAPI domdoc_get_namespaceURI(
1212     IXMLDOMDocument3 *iface,
1213     BSTR* namespaceURI )
1214 {
1215     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1216     return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), namespaceURI );
1217 }
1218
1219
1220 static HRESULT WINAPI domdoc_get_prefix(
1221     IXMLDOMDocument3 *iface,
1222     BSTR* prefixString )
1223 {
1224     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1225     return IXMLDOMNode_get_prefix( IXMLDOMNode_from_impl(&This->node), prefixString );
1226 }
1227
1228
1229 static HRESULT WINAPI domdoc_get_baseName(
1230     IXMLDOMDocument3 *iface,
1231     BSTR* nameString )
1232 {
1233     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1234     return IXMLDOMNode_get_baseName( IXMLDOMNode_from_impl(&This->node), nameString );
1235 }
1236
1237
1238 static HRESULT WINAPI domdoc_transformNodeToObject(
1239     IXMLDOMDocument3 *iface,
1240     IXMLDOMNode* stylesheet,
1241     VARIANT outputObject)
1242 {
1243     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1244     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), stylesheet, outputObject );
1245 }
1246
1247
1248 static HRESULT WINAPI domdoc_get_doctype(
1249     IXMLDOMDocument3 *iface,
1250     IXMLDOMDocumentType** documentType )
1251 {
1252     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1253     FIXME("(%p)\n", This);
1254     return E_NOTIMPL;
1255 }
1256
1257
1258 static HRESULT WINAPI domdoc_get_implementation(
1259     IXMLDOMDocument3 *iface,
1260     IXMLDOMImplementation** impl )
1261 {
1262     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1263
1264     TRACE("(%p)->(%p)\n", This, impl);
1265
1266     if(!impl)
1267         return E_INVALIDARG;
1268
1269     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1270
1271     return S_OK;
1272 }
1273
1274 static HRESULT WINAPI domdoc_get_documentElement(
1275     IXMLDOMDocument3 *iface,
1276     IXMLDOMElement** DOMElement )
1277 {
1278     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279     IXMLDOMNode *element_node;
1280     xmlNodePtr root;
1281     HRESULT hr;
1282
1283     TRACE("(%p)->(%p)\n", This, DOMElement);
1284
1285     if(!DOMElement)
1286         return E_INVALIDARG;
1287
1288     *DOMElement = NULL;
1289
1290     root = xmlDocGetRootElement( get_doc(This) );
1291     if ( !root )
1292         return S_FALSE;
1293
1294     element_node = create_node( root );
1295     if(!element_node) return S_FALSE;
1296
1297     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1298     IXMLDOMNode_Release(element_node);
1299
1300     return hr;
1301 }
1302
1303
1304 static HRESULT WINAPI domdoc_put_documentElement(
1305     IXMLDOMDocument3 *iface,
1306     IXMLDOMElement* DOMElement )
1307 {
1308     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1309     IXMLDOMNode *elementNode;
1310     xmlNodePtr oldRoot;
1311     xmlnode *xmlNode;
1312     HRESULT hr;
1313
1314     TRACE("(%p)->(%p)\n", This, DOMElement);
1315
1316     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1317     if(FAILED(hr))
1318         return hr;
1319
1320     xmlNode = get_node_obj( elementNode );
1321     if(!xmlNode) {
1322         FIXME("elementNode is not our object\n");
1323         return E_FAIL;
1324     }
1325
1326     if(!xmlNode->node->parent)
1327         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1328             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1329
1330     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1331     IXMLDOMNode_Release( elementNode );
1332
1333     if(oldRoot)
1334         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1335
1336     return S_OK;
1337 }
1338
1339
1340 static HRESULT WINAPI domdoc_createElement(
1341     IXMLDOMDocument3 *iface,
1342     BSTR tagname,
1343     IXMLDOMElement** element )
1344 {
1345     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1346     IXMLDOMNode *node;
1347     VARIANT type;
1348     HRESULT hr;
1349
1350     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1351
1352     if (!element || !tagname) return E_INVALIDARG;
1353
1354     V_VT(&type) = VT_I1;
1355     V_I1(&type) = NODE_ELEMENT;
1356
1357     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1358     if (hr == S_OK)
1359     {
1360         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1361         IXMLDOMNode_Release(node);
1362     }
1363
1364     return hr;
1365 }
1366
1367
1368 static HRESULT WINAPI domdoc_createDocumentFragment(
1369     IXMLDOMDocument3 *iface,
1370     IXMLDOMDocumentFragment** frag )
1371 {
1372     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1373     IXMLDOMNode *node;
1374     VARIANT type;
1375     HRESULT hr;
1376
1377     TRACE("(%p)->(%p)\n", This, frag);
1378
1379     if (!frag) return E_INVALIDARG;
1380
1381     *frag = NULL;
1382
1383     V_VT(&type) = VT_I1;
1384     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1385
1386     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1387     if (hr == S_OK)
1388     {
1389         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1390         IXMLDOMNode_Release(node);
1391     }
1392
1393     return hr;
1394 }
1395
1396
1397 static HRESULT WINAPI domdoc_createTextNode(
1398     IXMLDOMDocument3 *iface,
1399     BSTR data,
1400     IXMLDOMText** text )
1401 {
1402     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1403     IXMLDOMNode *node;
1404     VARIANT type;
1405     HRESULT hr;
1406
1407     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1408
1409     if (!text) return E_INVALIDARG;
1410
1411     *text = NULL;
1412
1413     V_VT(&type) = VT_I1;
1414     V_I1(&type) = NODE_TEXT;
1415
1416     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1417     if (hr == S_OK)
1418     {
1419         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1420         IXMLDOMNode_Release(node);
1421         hr = IXMLDOMText_put_data(*text, data);
1422     }
1423
1424     return hr;
1425 }
1426
1427
1428 static HRESULT WINAPI domdoc_createComment(
1429     IXMLDOMDocument3 *iface,
1430     BSTR data,
1431     IXMLDOMComment** comment )
1432 {
1433     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1434     VARIANT type;
1435     HRESULT hr;
1436     IXMLDOMNode *node;
1437
1438     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1439
1440     if (!comment) return E_INVALIDARG;
1441
1442     *comment = NULL;
1443
1444     V_VT(&type) = VT_I1;
1445     V_I1(&type) = NODE_COMMENT;
1446
1447     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1448     if (hr == S_OK)
1449     {
1450         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1451         IXMLDOMNode_Release(node);
1452         hr = IXMLDOMComment_put_data(*comment, data);
1453     }
1454
1455     return hr;
1456 }
1457
1458
1459 static HRESULT WINAPI domdoc_createCDATASection(
1460     IXMLDOMDocument3 *iface,
1461     BSTR data,
1462     IXMLDOMCDATASection** cdata )
1463 {
1464     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1465     IXMLDOMNode *node;
1466     VARIANT type;
1467     HRESULT hr;
1468
1469     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1470
1471     if (!cdata) return E_INVALIDARG;
1472
1473     *cdata = NULL;
1474
1475     V_VT(&type) = VT_I1;
1476     V_I1(&type) = NODE_CDATA_SECTION;
1477
1478     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1479     if (hr == S_OK)
1480     {
1481         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1482         IXMLDOMNode_Release(node);
1483         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1484     }
1485
1486     return hr;
1487 }
1488
1489
1490 static HRESULT WINAPI domdoc_createProcessingInstruction(
1491     IXMLDOMDocument3 *iface,
1492     BSTR target,
1493     BSTR data,
1494     IXMLDOMProcessingInstruction** pi )
1495 {
1496     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1497     IXMLDOMNode *node;
1498     VARIANT type;
1499     HRESULT hr;
1500
1501     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1502
1503     if (!pi) return E_INVALIDARG;
1504
1505     *pi = NULL;
1506
1507     V_VT(&type) = VT_I1;
1508     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1509
1510     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1511     if (hr == S_OK)
1512     {
1513         VARIANT v_data;
1514         xmlnode *node_obj;
1515
1516         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1517         node_obj = get_node_obj(node);
1518         V_VT(&v_data)   = VT_BSTR;
1519         V_BSTR(&v_data) = data;
1520
1521         hr = node_put_value(node_obj, &v_data);
1522
1523         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1524         IXMLDOMNode_Release(node);
1525     }
1526
1527     return hr;
1528 }
1529
1530
1531 static HRESULT WINAPI domdoc_createAttribute(
1532     IXMLDOMDocument3 *iface,
1533     BSTR name,
1534     IXMLDOMAttribute** attribute )
1535 {
1536     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1537     IXMLDOMNode *node;
1538     VARIANT type;
1539     HRESULT hr;
1540
1541     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1542
1543     if (!attribute || !name) return E_INVALIDARG;
1544
1545     V_VT(&type) = VT_I1;
1546     V_I1(&type) = NODE_ATTRIBUTE;
1547
1548     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1549     if (hr == S_OK)
1550     {
1551         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1552         IXMLDOMNode_Release(node);
1553     }
1554
1555     return hr;
1556 }
1557
1558
1559 static HRESULT WINAPI domdoc_createEntityReference(
1560     IXMLDOMDocument3 *iface,
1561     BSTR name,
1562     IXMLDOMEntityReference** entityref )
1563 {
1564     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1565     IXMLDOMNode *node;
1566     VARIANT type;
1567     HRESULT hr;
1568
1569     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1570
1571     if (!entityref) return E_INVALIDARG;
1572
1573     *entityref = NULL;
1574
1575     V_VT(&type) = VT_I1;
1576     V_I1(&type) = NODE_ENTITY_REFERENCE;
1577
1578     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1579     if (hr == S_OK)
1580     {
1581         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1582         IXMLDOMNode_Release(node);
1583     }
1584
1585     return hr;
1586 }
1587
1588
1589 static HRESULT WINAPI domdoc_getElementsByTagName(
1590     IXMLDOMDocument3 *iface,
1591     BSTR tagName,
1592     IXMLDOMNodeList** resultList )
1593 {
1594     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1595     HRESULT hr;
1596
1597     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagName), resultList);
1598
1599     if (!tagName || !resultList) return E_INVALIDARG;
1600
1601     if (tagName[0] == '*' && tagName[1] == 0)
1602     {
1603         static const WCHAR formatallW[] = {'/','/','*',0};
1604         hr = queryresult_create((xmlNodePtr)get_doc(This), formatallW, resultList);
1605     }
1606     else
1607     {
1608         static const WCHAR xpathformat[] =
1609             { '/','/','*','[','l','o','c','a','l','-','n','a','m','e','(',')','=','\'' };
1610         static const WCHAR closeW[] = { '\'',']',0 };
1611
1612         LPWSTR pattern;
1613         WCHAR *ptr;
1614         INT length;
1615
1616         length = lstrlenW(tagName);
1617
1618         /* without two WCHARs from format specifier */
1619         ptr = pattern = heap_alloc(sizeof(xpathformat) + length*sizeof(WCHAR) + sizeof(closeW));
1620
1621         memcpy(ptr, xpathformat, sizeof(xpathformat));
1622         ptr += sizeof(xpathformat)/sizeof(WCHAR);
1623         memcpy(ptr, tagName, length*sizeof(WCHAR));
1624         ptr += length;
1625         memcpy(ptr, closeW, sizeof(closeW));
1626
1627         hr = queryresult_create((xmlNodePtr)get_doc(This), pattern, resultList);
1628         heap_free(pattern);
1629     }
1630
1631     return hr;
1632 }
1633
1634 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1635 {
1636     VARIANT tmp;
1637     HRESULT hr;
1638
1639     VariantInit(&tmp);
1640     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1641     if(FAILED(hr))
1642         return E_INVALIDARG;
1643
1644     *type = V_I4(&tmp);
1645
1646     return S_OK;
1647 }
1648
1649 static HRESULT WINAPI domdoc_createNode(
1650     IXMLDOMDocument3 *iface,
1651     VARIANT Type,
1652     BSTR name,
1653     BSTR namespaceURI,
1654     IXMLDOMNode** node )
1655 {
1656     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1657     DOMNodeType node_type;
1658     xmlNodePtr xmlnode;
1659     xmlChar *xml_name, *href;
1660     HRESULT hr;
1661
1662     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1663
1664     if(!node) return E_INVALIDARG;
1665
1666     hr = get_node_type(Type, &node_type);
1667     if(FAILED(hr)) return hr;
1668
1669     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1670         FIXME("nodes with namespaces currently not supported.\n");
1671
1672     TRACE("node_type %d\n", node_type);
1673
1674     /* exit earlier for types that need name */
1675     switch(node_type)
1676     {
1677     case NODE_ELEMENT:
1678     case NODE_ATTRIBUTE:
1679     case NODE_ENTITY_REFERENCE:
1680     case NODE_PROCESSING_INSTRUCTION:
1681         if (!name || *name == 0) return E_FAIL;
1682     default:
1683         break;
1684     }
1685
1686     xml_name = xmlChar_from_wchar(name);
1687     /* prevent empty href to be allocated */
1688     href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1689
1690     switch(node_type)
1691     {
1692     case NODE_ELEMENT:
1693     {
1694         xmlChar *local, *prefix;
1695
1696         local = xmlSplitQName2(xml_name, &prefix);
1697
1698         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1699
1700         /* allow to create default namespace xmlns= */
1701         if (local || (href && *href))
1702         {
1703             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1704             xmlSetNs(xmlnode, ns);
1705         }
1706
1707         xmlFree(local);
1708         xmlFree(prefix);
1709
1710         break;
1711     }
1712     case NODE_ATTRIBUTE:
1713         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1714         break;
1715     case NODE_TEXT:
1716         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1717         break;
1718     case NODE_CDATA_SECTION:
1719         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1720         break;
1721     case NODE_ENTITY_REFERENCE:
1722         xmlnode = xmlNewReference(get_doc(This), xml_name);
1723         break;
1724     case NODE_PROCESSING_INSTRUCTION:
1725 #ifdef HAVE_XMLNEWDOCPI
1726         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1727 #else
1728         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1729         xmlnode = NULL;
1730 #endif
1731         break;
1732     case NODE_COMMENT:
1733         xmlnode = xmlNewDocComment(get_doc(This), NULL);
1734         break;
1735     case NODE_DOCUMENT_FRAGMENT:
1736         xmlnode = xmlNewDocFragment(get_doc(This));
1737         break;
1738     /* unsupported types */
1739     case NODE_DOCUMENT:
1740     case NODE_DOCUMENT_TYPE:
1741     case NODE_ENTITY:
1742     case NODE_NOTATION:
1743         heap_free(xml_name);
1744         return E_INVALIDARG;
1745     default:
1746         FIXME("unhandled node type %d\n", node_type);
1747         xmlnode = NULL;
1748         break;
1749     }
1750
1751     *node = create_node(xmlnode);
1752     heap_free(xml_name);
1753     heap_free(href);
1754
1755     if(*node)
1756     {
1757         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1758         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1759         return S_OK;
1760     }
1761
1762     return E_FAIL;
1763 }
1764
1765 static HRESULT WINAPI domdoc_nodeFromID(
1766     IXMLDOMDocument3 *iface,
1767     BSTR idString,
1768     IXMLDOMNode** node )
1769 {
1770     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1771     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1772     return E_NOTIMPL;
1773 }
1774
1775 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1776 {
1777     domdoc *This = obj;
1778     xmlDocPtr xmldoc;
1779
1780     xmldoc = doparse(This, ptr, len);
1781     if(xmldoc) {
1782         xmldoc->_private = create_priv();
1783         return attach_xmldoc(This, xmldoc);
1784     }
1785
1786     return S_OK;
1787 }
1788
1789 static HRESULT doread( domdoc *This, LPWSTR filename )
1790 {
1791     bsc_t *bsc;
1792     HRESULT hr;
1793
1794     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1795     if(FAILED(hr))
1796         return hr;
1797
1798     if(This->bsc)
1799         detach_bsc(This->bsc);
1800
1801     This->bsc = bsc;
1802     return S_OK;
1803 }
1804
1805 static HRESULT WINAPI domdoc_load(
1806     IXMLDOMDocument3 *iface,
1807     VARIANT xmlSource,
1808     VARIANT_BOOL* isSuccessful )
1809 {
1810     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1811     LPWSTR filename = NULL;
1812     HRESULT hr = S_FALSE;
1813     IXMLDOMDocument3 *pNewDoc = NULL;
1814     IStream *pStream = NULL;
1815     xmlDocPtr xmldoc;
1816
1817     TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
1818
1819     *isSuccessful = VARIANT_FALSE;
1820
1821     assert( &This->node );
1822
1823     switch( V_VT(&xmlSource) )
1824     {
1825     case VT_BSTR:
1826         filename = V_BSTR(&xmlSource);
1827         break;
1828     case VT_UNKNOWN:
1829         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
1830         if(hr == S_OK)
1831         {
1832             if(pNewDoc)
1833             {
1834                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
1835                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
1836                 hr = attach_xmldoc(This, xmldoc);
1837
1838                 if(SUCCEEDED(hr))
1839                     *isSuccessful = VARIANT_TRUE;
1840
1841                 return hr;
1842             }
1843         }
1844         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
1845         if(hr == S_OK)
1846         {
1847             IPersistStream *pDocStream;
1848             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
1849             if(hr == S_OK)
1850             {
1851                 hr = IPersistStream_Load(pDocStream, pStream);
1852                 IStream_Release(pStream);
1853                 if(hr == S_OK)
1854                 {
1855                     *isSuccessful = VARIANT_TRUE;
1856
1857                     TRACE("Using IStream to load Document\n");
1858                     return S_OK;
1859                 }
1860                 else
1861                 {
1862                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
1863                 }
1864             }
1865             else
1866             {
1867                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
1868             }
1869         }
1870         else
1871         {
1872             /* ISequentialStream */
1873             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
1874         }
1875         break;
1876      default:
1877             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
1878      }
1879
1880     TRACE("filename (%s)\n", debugstr_w(filename));
1881
1882     if ( filename )
1883     {
1884         hr = doread( This, filename );
1885
1886         if ( FAILED(hr) )
1887             This->error = E_FAIL;
1888         else
1889         {
1890             hr = This->error = S_OK;
1891             *isSuccessful = VARIANT_TRUE;
1892         }
1893     }
1894
1895     if(!filename || FAILED(hr)) {
1896         xmldoc = xmlNewDoc(NULL);
1897         xmldoc->_private = create_priv();
1898         hr = attach_xmldoc(This, xmldoc);
1899         if(SUCCEEDED(hr))
1900             hr = S_FALSE;
1901     }
1902
1903     TRACE("ret (%d)\n", hr);
1904
1905     return hr;
1906 }
1907
1908
1909 static HRESULT WINAPI domdoc_get_readyState(
1910     IXMLDOMDocument3 *iface,
1911     LONG *value )
1912 {
1913     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1914     FIXME("(%p)->(%p)\n", This, value);
1915     return E_NOTIMPL;
1916 }
1917
1918
1919 static HRESULT WINAPI domdoc_get_parseError(
1920     IXMLDOMDocument3 *iface,
1921     IXMLDOMParseError** errorObj )
1922 {
1923     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1924     static const WCHAR err[] = {'e','r','r','o','r',0};
1925     BSTR error_string = NULL;
1926
1927     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
1928
1929     if(This->error)
1930         error_string = SysAllocString(err);
1931
1932     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
1933     if(!*errorObj) return E_OUTOFMEMORY;
1934     return S_OK;
1935 }
1936
1937
1938 static HRESULT WINAPI domdoc_get_url(
1939     IXMLDOMDocument3 *iface,
1940     BSTR* urlString )
1941 {
1942     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1943     FIXME("(%p)->(%p)\n", This, urlString);
1944     return E_NOTIMPL;
1945 }
1946
1947
1948 static HRESULT WINAPI domdoc_get_async(
1949     IXMLDOMDocument3 *iface,
1950     VARIANT_BOOL* isAsync )
1951 {
1952     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1953
1954     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
1955     *isAsync = This->async;
1956     return S_OK;
1957 }
1958
1959
1960 static HRESULT WINAPI domdoc_put_async(
1961     IXMLDOMDocument3 *iface,
1962     VARIANT_BOOL isAsync )
1963 {
1964     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1965
1966     TRACE("(%p)->(%d)\n", This, isAsync);
1967     This->async = isAsync;
1968     return S_OK;
1969 }
1970
1971
1972 static HRESULT WINAPI domdoc_abort(
1973     IXMLDOMDocument3 *iface )
1974 {
1975     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1976     FIXME("%p\n", This);
1977     return E_NOTIMPL;
1978 }
1979
1980
1981 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
1982 {
1983     UINT len;
1984     LPSTR str;
1985
1986     len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
1987     str = heap_alloc( len );
1988     if ( !str )
1989         return FALSE;
1990     WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
1991     *plen = len;
1992     *pstr = str;
1993     return TRUE;
1994 }
1995
1996 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
1997 static HRESULT WINAPI domdoc_loadXML(
1998     IXMLDOMDocument3 *iface,
1999     BSTR bstrXML,
2000     VARIANT_BOOL* isSuccessful )
2001 {
2002     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2003     xmlDocPtr xmldoc = NULL;
2004     HRESULT hr = S_FALSE, hr2;
2005     char *str;
2006     int len;
2007
2008     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2009
2010     assert ( &This->node );
2011
2012     if ( isSuccessful )
2013     {
2014         *isSuccessful = VARIANT_FALSE;
2015
2016         if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2017         {
2018             xmldoc = doparse(This, str, len);
2019             heap_free( str );
2020             if ( !xmldoc )
2021                 This->error = E_FAIL;
2022             else
2023             {
2024                 hr = This->error = S_OK;
2025                 *isSuccessful = VARIANT_TRUE;
2026                 TRACE("parsed document %p\n", xmldoc);
2027             }
2028         }
2029     }
2030     if(!xmldoc)
2031         xmldoc = xmlNewDoc(NULL);
2032
2033     xmldoc->_private = create_priv();
2034
2035     hr2 = attach_xmldoc(This, xmldoc);
2036     if( FAILED(hr2) )
2037         hr = hr2;
2038
2039     return hr;
2040 }
2041
2042 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer,
2043                                              int len)
2044 {
2045     DWORD written = -1;
2046
2047     if(!WriteFile(ctx, buffer, len, &written, NULL))
2048     {
2049         WARN("write error\n");
2050         return -1;
2051     }
2052     else
2053         return written;
2054 }
2055
2056 static int XMLCALL domdoc_save_closecallback(void *ctx)
2057 {
2058     return CloseHandle(ctx) ? 0 : -1;
2059 }
2060
2061 static HRESULT WINAPI domdoc_save(
2062     IXMLDOMDocument3 *iface,
2063     VARIANT destination )
2064 {
2065     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2066     HANDLE handle;
2067     xmlSaveCtxtPtr ctx;
2068     xmlNodePtr xmldecl;
2069     HRESULT ret = S_OK;
2070
2071     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2072           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2073
2074     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2075     {
2076         FIXME("Unhandled vt %d\n", V_VT(&destination));
2077         return S_FALSE;
2078     }
2079
2080     if(V_VT(&destination) == VT_UNKNOWN)
2081     {
2082         IUnknown *pUnk = V_UNKNOWN(&destination);
2083         IXMLDOMDocument2 *pDocument;
2084
2085         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&pDocument);
2086         if(ret == S_OK)
2087         {
2088             VARIANT_BOOL success;
2089             BSTR xml;
2090
2091             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2092             if(ret == S_OK)
2093             {
2094                 ret = IXMLDOMDocument3_loadXML(pDocument, xml, &success);
2095                 SysFreeString(xml);
2096             }
2097
2098             IXMLDOMDocument3_Release(pDocument);
2099         }
2100
2101         TRACE("ret %d\n", ret);
2102
2103         return ret;
2104     }
2105
2106     handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2107                           NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2108     if( handle == INVALID_HANDLE_VALUE )
2109     {
2110         WARN("failed to create file\n");
2111         return S_FALSE;
2112     }
2113
2114     /* disable top XML declaration */
2115     ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2116                       handle, NULL, XML_SAVE_NO_DECL);
2117     if (!ctx)
2118     {
2119         CloseHandle(handle);
2120         return S_FALSE;
2121     }
2122
2123     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2124     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2125     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2126
2127     /* will close file through close callback */
2128     xmlSaveClose(ctx);
2129
2130     return ret;
2131 }
2132
2133 static HRESULT WINAPI domdoc_get_validateOnParse(
2134     IXMLDOMDocument3 *iface,
2135     VARIANT_BOOL* isValidating )
2136 {
2137     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2138     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2139     *isValidating = This->validating;
2140     return S_OK;
2141 }
2142
2143
2144 static HRESULT WINAPI domdoc_put_validateOnParse(
2145     IXMLDOMDocument3 *iface,
2146     VARIANT_BOOL isValidating )
2147 {
2148     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2149     TRACE("(%p)->(%d)\n", This, isValidating);
2150     This->validating = isValidating;
2151     return S_OK;
2152 }
2153
2154
2155 static HRESULT WINAPI domdoc_get_resolveExternals(
2156     IXMLDOMDocument3 *iface,
2157     VARIANT_BOOL* isResolving )
2158 {
2159     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2160     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2161     *isResolving = This->resolving;
2162     return S_OK;
2163 }
2164
2165
2166 static HRESULT WINAPI domdoc_put_resolveExternals(
2167     IXMLDOMDocument3 *iface,
2168     VARIANT_BOOL isResolving )
2169 {
2170     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2171     TRACE("(%p)->(%d)\n", This, isResolving);
2172     This->resolving = isResolving;
2173     return S_OK;
2174 }
2175
2176
2177 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2178     IXMLDOMDocument3 *iface,
2179     VARIANT_BOOL* isPreserving )
2180 {
2181     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2182     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->preserving);
2183     *isPreserving = This->preserving;
2184     return S_OK;
2185 }
2186
2187
2188 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2189     IXMLDOMDocument3 *iface,
2190     VARIANT_BOOL isPreserving )
2191 {
2192     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2193     TRACE("(%p)->(%d)\n", This, isPreserving);
2194     This->preserving = isPreserving;
2195     return S_OK;
2196 }
2197
2198
2199 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2200     IXMLDOMDocument3 *iface,
2201     VARIANT readyStateChangeSink )
2202 {
2203     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2204     FIXME("%p\n", This);
2205     return E_NOTIMPL;
2206 }
2207
2208
2209 static HRESULT WINAPI domdoc_put_onDataAvailable(
2210     IXMLDOMDocument3 *iface,
2211     VARIANT onDataAvailableSink )
2212 {
2213     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2214     FIXME("%p\n", This);
2215     return E_NOTIMPL;
2216 }
2217
2218 static HRESULT WINAPI domdoc_put_onTransformNode(
2219     IXMLDOMDocument3 *iface,
2220     VARIANT onTransformNodeSink )
2221 {
2222     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2223     FIXME("%p\n", This);
2224     return E_NOTIMPL;
2225 }
2226
2227 static HRESULT WINAPI domdoc_get_namespaces(
2228     IXMLDOMDocument3* iface,
2229     IXMLDOMSchemaCollection** schemaCollection )
2230 {
2231     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2232     FIXME("(%p)->(%p)\n", This, schemaCollection);
2233     return E_NOTIMPL;
2234 }
2235
2236 static HRESULT WINAPI domdoc_get_schemas(
2237     IXMLDOMDocument3* iface,
2238     VARIANT* var1 )
2239 {
2240     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2241     HRESULT hr = S_FALSE;
2242     IXMLDOMSchemaCollection *cur_schema = This->schema;
2243
2244     TRACE("(%p)->(%p)\n", This, var1);
2245
2246     VariantInit(var1); /* Test shows we don't call VariantClear here */
2247     V_VT(var1) = VT_NULL;
2248
2249     if(cur_schema)
2250     {
2251         hr = IXMLDOMSchemaCollection_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2252         if(SUCCEEDED(hr))
2253             V_VT(var1) = VT_DISPATCH;
2254     }
2255     return hr;
2256 }
2257
2258 static HRESULT WINAPI domdoc_putref_schemas(
2259     IXMLDOMDocument3* iface,
2260     VARIANT var1)
2261 {
2262     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2263     HRESULT hr = E_FAIL;
2264     IXMLDOMSchemaCollection *new_schema = NULL;
2265
2266     FIXME("(%p): semi-stub\n", This);
2267     switch(V_VT(&var1))
2268     {
2269     case VT_UNKNOWN:
2270         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2271         break;
2272
2273     case VT_DISPATCH:
2274         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2275         break;
2276
2277     case VT_NULL:
2278     case VT_EMPTY:
2279         hr = S_OK;
2280         break;
2281
2282     default:
2283         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2284     }
2285
2286     if(SUCCEEDED(hr))
2287     {
2288         IXMLDOMSchemaCollection *old_schema = InterlockedExchangePointer((void**)&This->schema, new_schema);
2289         if(old_schema) IXMLDOMSchemaCollection_Release(old_schema);
2290     }
2291
2292     return hr;
2293 }
2294
2295 static HRESULT WINAPI domdoc_validate(
2296     IXMLDOMDocument3* iface,
2297     IXMLDOMParseError** err)
2298 {
2299     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2300     FIXME("(%p)->(%p)\n", This, err);
2301     return E_NOTIMPL;
2302 }
2303
2304 static HRESULT WINAPI domdoc_setProperty(
2305     IXMLDOMDocument3* iface,
2306     BSTR p,
2307     VARIANT var)
2308 {
2309     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2310
2311     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2312
2313     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2314     {
2315         VARIANT varStr;
2316         HRESULT hr;
2317         BSTR bstr;
2318
2319         V_VT(&varStr) = VT_EMPTY;
2320         if (V_VT(&var) != VT_BSTR)
2321         {
2322             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2323                 return hr;
2324             bstr = V_BSTR(&varStr);
2325         }
2326         else
2327             bstr = V_BSTR(&var);
2328
2329         hr = S_OK;
2330         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2331             This->properties->XPath = TRUE;
2332         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2333             This->properties->XPath = FALSE;
2334         else
2335             hr = E_FAIL;
2336
2337         VariantClear(&varStr);
2338         return hr;
2339     }
2340     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2341     {
2342         VARIANT varStr;
2343         HRESULT hr;
2344         BSTR bstr;
2345         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2346         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2347         xmlXPathContextPtr ctx;
2348         struct list *pNsList;
2349         select_ns_entry* pNsEntry = NULL;
2350
2351         V_VT(&varStr) = VT_EMPTY;
2352         if (V_VT(&var) != VT_BSTR)
2353         {
2354             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2355                 return hr;
2356             bstr = V_BSTR(&varStr);
2357         }
2358         else
2359             bstr = V_BSTR(&var);
2360
2361         hr = S_OK;
2362
2363         pNsList = &(This->properties->selectNsList);
2364         clear_selectNsList(pNsList);
2365         heap_free(nsStr);
2366         nsStr = xmlChar_from_wchar(bstr);
2367
2368
2369         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2370
2371         This->properties->selectNsStr = nsStr;
2372         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2373         if (bstr && *bstr)
2374         {
2375             ctx = xmlXPathNewContext(This->node.node->doc);
2376             pTokBegin = nsStr;
2377             pTokEnd = nsStr;
2378             for (; *pTokBegin; pTokBegin = pTokEnd)
2379             {
2380                 if (pNsEntry != NULL)
2381                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2382                 else
2383                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2384
2385                 while (*pTokBegin == ' ')
2386                     ++pTokBegin;
2387                 pTokEnd = pTokBegin;
2388                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2389                     ++pTokEnd;
2390
2391                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2392                 {
2393                     hr = E_FAIL;
2394                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2395                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2396                     continue;
2397                 }
2398
2399                 pTokBegin += 5;
2400                 if (*pTokBegin == '=')
2401                 {
2402                     /*valid for XSLPattern?*/
2403                     FIXME("Setting default xmlns not supported - skipping.\n");
2404                     pTokBegin = pTokEnd;
2405                     continue;
2406                 }
2407                 else if (*pTokBegin == ':')
2408                 {
2409                     pNsEntry->prefix = ++pTokBegin;
2410                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2411                         ;
2412
2413                     if (pTokInner == pTokEnd)
2414                     {
2415                         hr = E_FAIL;
2416                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2417                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2418                         continue;
2419                     }
2420
2421                     pNsEntry->prefix_end = *pTokInner;
2422                     *pTokInner = 0;
2423                     ++pTokInner;
2424
2425                     if (pTokEnd-pTokInner > 1 &&
2426                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2427                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2428                     {
2429                         pNsEntry->href = ++pTokInner;
2430                         pNsEntry->href_end = *(pTokEnd-1);
2431                         *(pTokEnd-1) = 0;
2432                         list_add_tail(pNsList, &pNsEntry->entry);
2433                         /*let libxml figure out if they're valid from here ;)*/
2434                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2435                         {
2436                             hr = E_FAIL;
2437                         }
2438                         pNsEntry = NULL;
2439                         continue;
2440                     }
2441                     else
2442                     {
2443                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2444                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2445                         list_add_tail(pNsList, &pNsEntry->entry);
2446
2447                         pNsEntry = NULL;
2448                         hr = E_FAIL;
2449                         continue;
2450                     }
2451                 }
2452                 else
2453                 {
2454                     hr = E_FAIL;
2455                     continue;
2456                 }
2457             }
2458             heap_free(pNsEntry);
2459             xmlXPathFreeContext(ctx);
2460         }
2461
2462         VariantClear(&varStr);
2463         return hr;
2464     }
2465     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0)
2466     {
2467         /* Ignore */
2468         FIXME("Ignoring property ProhibitDTD, value %d\n", V_BOOL(&var));
2469         return S_OK;
2470     }
2471
2472     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2473     return E_FAIL;
2474 }
2475
2476 static HRESULT WINAPI domdoc_getProperty(
2477     IXMLDOMDocument3* iface,
2478     BSTR p,
2479     VARIANT* var)
2480 {
2481     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2482
2483     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2484
2485     if (!var)
2486         return E_INVALIDARG;
2487
2488     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2489     {
2490         V_VT(var) = VT_BSTR;
2491         V_BSTR(var) = This->properties->XPath ?
2492                       SysAllocString(PropValueXPathW) :
2493                       SysAllocString(PropValueXSLPatternW);
2494         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2495     }
2496     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2497     {
2498         int lenA, lenW;
2499         BSTR rebuiltStr, cur;
2500         const xmlChar *nsStr;
2501         struct list *pNsList;
2502         select_ns_entry* pNsEntry;
2503
2504         V_VT(var) = VT_BSTR;
2505         nsStr = This->properties->selectNsStr;
2506         pNsList = &This->properties->selectNsList;
2507         lenA = This->properties->selectNsStr_len;
2508         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2509         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2510         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2511         cur = rebuiltStr;
2512         /* this is fine because all of the chars that end tokens are ASCII*/
2513         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2514         {
2515             while (*cur != 0) ++cur;
2516             if (pNsEntry->prefix_end)
2517             {
2518                 *cur = pNsEntry->prefix_end;
2519                 while (*cur != 0) ++cur;
2520             }
2521
2522             if (pNsEntry->href_end)
2523             {
2524                 *cur = pNsEntry->href_end;
2525             }
2526         }
2527         V_BSTR(var) = SysAllocString(rebuiltStr);
2528         heap_free(rebuiltStr);
2529         return S_OK;
2530     }
2531
2532     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2533     return E_FAIL;
2534 }
2535
2536 static HRESULT WINAPI domdoc_validateNode(
2537     IXMLDOMDocument3* iface,
2538     IXMLDOMNode* node,
2539     IXMLDOMParseError** error)
2540 {
2541     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2542     FIXME("(%p)->(%p %p): stub\n", This, node, error);
2543     return E_NOTIMPL;
2544 }
2545
2546 static HRESULT WINAPI domdoc_importNode(
2547     IXMLDOMDocument3* iface,
2548     IXMLDOMNode* node,
2549     VARIANT_BOOL deep,
2550     IXMLDOMNode** clone)
2551 {
2552     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2553     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2554     return E_NOTIMPL;
2555 }
2556
2557 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2558 {
2559     domdoc_QueryInterface,
2560     domdoc_AddRef,
2561     domdoc_Release,
2562     domdoc_GetTypeInfoCount,
2563     domdoc_GetTypeInfo,
2564     domdoc_GetIDsOfNames,
2565     domdoc_Invoke,
2566     domdoc_get_nodeName,
2567     domdoc_get_nodeValue,
2568     domdoc_put_nodeValue,
2569     domdoc_get_nodeType,
2570     domdoc_get_parentNode,
2571     domdoc_get_childNodes,
2572     domdoc_get_firstChild,
2573     domdoc_get_lastChild,
2574     domdoc_get_previousSibling,
2575     domdoc_get_nextSibling,
2576     domdoc_get_attributes,
2577     domdoc_insertBefore,
2578     domdoc_replaceChild,
2579     domdoc_removeChild,
2580     domdoc_appendChild,
2581     domdoc_hasChildNodes,
2582     domdoc_get_ownerDocument,
2583     domdoc_cloneNode,
2584     domdoc_get_nodeTypeString,
2585     domdoc_get_text,
2586     domdoc_put_text,
2587     domdoc_get_specified,
2588     domdoc_get_definition,
2589     domdoc_get_nodeTypedValue,
2590     domdoc_put_nodeTypedValue,
2591     domdoc_get_dataType,
2592     domdoc_put_dataType,
2593     domdoc_get_xml,
2594     domdoc_transformNode,
2595     domdoc_selectNodes,
2596     domdoc_selectSingleNode,
2597     domdoc_get_parsed,
2598     domdoc_get_namespaceURI,
2599     domdoc_get_prefix,
2600     domdoc_get_baseName,
2601     domdoc_transformNodeToObject,
2602     domdoc_get_doctype,
2603     domdoc_get_implementation,
2604     domdoc_get_documentElement,
2605     domdoc_put_documentElement,
2606     domdoc_createElement,
2607     domdoc_createDocumentFragment,
2608     domdoc_createTextNode,
2609     domdoc_createComment,
2610     domdoc_createCDATASection,
2611     domdoc_createProcessingInstruction,
2612     domdoc_createAttribute,
2613     domdoc_createEntityReference,
2614     domdoc_getElementsByTagName,
2615     domdoc_createNode,
2616     domdoc_nodeFromID,
2617     domdoc_load,
2618     domdoc_get_readyState,
2619     domdoc_get_parseError,
2620     domdoc_get_url,
2621     domdoc_get_async,
2622     domdoc_put_async,
2623     domdoc_abort,
2624     domdoc_loadXML,
2625     domdoc_save,
2626     domdoc_get_validateOnParse,
2627     domdoc_put_validateOnParse,
2628     domdoc_get_resolveExternals,
2629     domdoc_put_resolveExternals,
2630     domdoc_get_preserveWhiteSpace,
2631     domdoc_put_preserveWhiteSpace,
2632     domdoc_put_onReadyStateChange,
2633     domdoc_put_onDataAvailable,
2634     domdoc_put_onTransformNode,
2635     domdoc_get_namespaces,
2636     domdoc_get_schemas,
2637     domdoc_putref_schemas,
2638     domdoc_validate,
2639     domdoc_setProperty,
2640     domdoc_getProperty,
2641     domdoc_validateNode,
2642     domdoc_importNode
2643 };
2644
2645 /* xmldoc implementation of IObjectWithSite */
2646 static HRESULT WINAPI
2647 xmldoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
2648 {
2649     domdoc *This = impl_from_IObjectWithSite(iface);
2650     return IXMLDocument_QueryInterface( (IXMLDocument *)This, riid, ppvObject );
2651 }
2652
2653 static ULONG WINAPI
2654 xmldoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
2655 {
2656     domdoc *This = impl_from_IObjectWithSite(iface);
2657     return IXMLDocument_AddRef((IXMLDocument *)This);
2658 }
2659
2660 static ULONG WINAPI
2661 xmldoc_ObjectWithSite_Release( IObjectWithSite* iface )
2662 {
2663     domdoc *This = impl_from_IObjectWithSite(iface);
2664     return IXMLDocument_Release((IXMLDocument *)This);
2665 }
2666
2667 static HRESULT WINAPI
2668 xmldoc_GetSite( IObjectWithSite *iface, REFIID iid, void ** ppvSite )
2669 {
2670     domdoc *This = impl_from_IObjectWithSite(iface);
2671
2672     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
2673
2674     if ( !This->site )
2675         return E_FAIL;
2676
2677     return IUnknown_QueryInterface( This->site, iid, ppvSite );
2678 }
2679
2680 static HRESULT WINAPI
2681 xmldoc_SetSite( IObjectWithSite *iface, IUnknown *punk )
2682 {
2683     domdoc *This = impl_from_IObjectWithSite(iface);
2684
2685     TRACE("(%p)->(%p)\n", iface, punk);
2686
2687     if(!punk)
2688     {
2689         if(This->site)
2690         {
2691             IUnknown_Release( This->site );
2692             This->site = NULL;
2693         }
2694
2695         return S_OK;
2696     }
2697
2698     IUnknown_AddRef( punk );
2699
2700     if(This->site)
2701         IUnknown_Release( This->site );
2702
2703     This->site = punk;
2704
2705     return S_OK;
2706 }
2707
2708 static const IObjectWithSiteVtbl domdocObjectSite =
2709 {
2710     xmldoc_ObjectWithSite_QueryInterface,
2711     xmldoc_ObjectWithSite_AddRef,
2712     xmldoc_ObjectWithSite_Release,
2713     xmldoc_SetSite,
2714     xmldoc_GetSite,
2715 };
2716
2717 static HRESULT WINAPI xmldoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
2718 {
2719     domdoc *This = impl_from_IObjectSafety(iface);
2720     return IXMLDocument_QueryInterface( (IXMLDocument *)This, riid, ppv );
2721 }
2722
2723 static ULONG WINAPI xmldoc_Safety_AddRef(IObjectSafety *iface)
2724 {
2725     domdoc *This = impl_from_IObjectSafety(iface);
2726     return IXMLDocument_AddRef((IXMLDocument *)This);
2727 }
2728
2729 static ULONG WINAPI xmldoc_Safety_Release(IObjectSafety *iface)
2730 {
2731     domdoc *This = impl_from_IObjectSafety(iface);
2732     return IXMLDocument_Release((IXMLDocument *)This);
2733 }
2734
2735 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
2736
2737 static HRESULT WINAPI xmldoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
2738         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
2739 {
2740     domdoc *This = impl_from_IObjectSafety(iface);
2741
2742     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
2743
2744     if(!pdwSupportedOptions || !pdwEnabledOptions)
2745         return E_POINTER;
2746
2747     *pdwSupportedOptions = SAFETY_SUPPORTED_OPTIONS;
2748     *pdwEnabledOptions = This->safeopt;
2749
2750     return S_OK;
2751 }
2752
2753 static HRESULT WINAPI xmldoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
2754         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
2755 {
2756     domdoc *This = impl_from_IObjectSafety(iface);
2757     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
2758
2759     if ((dwOptionSetMask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
2760         return E_FAIL;
2761
2762     This->safeopt = dwEnabledOptions & dwOptionSetMask & SAFETY_SUPPORTED_OPTIONS;
2763     return S_OK;
2764 }
2765
2766 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
2767     xmldoc_Safety_QueryInterface,
2768     xmldoc_Safety_AddRef,
2769     xmldoc_Safety_Release,
2770     xmldoc_Safety_GetInterfaceSafetyOptions,
2771     xmldoc_Safety_SetInterfaceSafetyOptions
2772 };
2773
2774
2775 static const tid_t domdoc_iface_tids[] = {
2776     IXMLDOMNode_tid,
2777     IXMLDOMDocument_tid,
2778     IXMLDOMDocument2_tid,
2779     0
2780 };
2781 static dispex_static_data_t domdoc_dispex = {
2782     NULL,
2783     IXMLDOMDocument2_tid,
2784     NULL,
2785     domdoc_iface_tids
2786 };
2787
2788 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
2789 {
2790     domdoc *doc;
2791
2792     doc = heap_alloc( sizeof (*doc) );
2793     if( !doc )
2794         return E_OUTOFMEMORY;
2795
2796     doc->lpVtbl = &domdoc_vtbl;
2797     doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
2798     doc->lpvtblIObjectWithSite = &domdocObjectSite;
2799     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
2800     doc->lpvtblISupportErrorInfo = &support_error_vtbl;
2801     doc->ref = 1;
2802     doc->async = VARIANT_TRUE;
2803     doc->validating = 0;
2804     doc->resolving = 0;
2805     doc->preserving = 0;
2806     doc->properties = properties_from_xmlDocPtr(xmldoc);
2807     doc->error = S_OK;
2808     doc->schema = NULL;
2809     doc->stream = NULL;
2810     doc->site = NULL;
2811     doc->safeopt = 0;
2812     doc->bsc = NULL;
2813
2814     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
2815
2816     *document = (IXMLDOMDocument3*)&doc->lpVtbl;
2817
2818     TRACE("returning iface %p\n", *document);
2819     return S_OK;
2820 }
2821
2822 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
2823 {
2824     xmlDocPtr xmldoc;
2825     HRESULT hr;
2826
2827     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
2828
2829     xmldoc = xmlNewDoc(NULL);
2830     if(!xmldoc)
2831         return E_OUTOFMEMORY;
2832
2833     xmldoc->_private = create_priv();
2834     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
2835
2836     hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
2837     if(FAILED(hr))
2838     {
2839         xmlFreeDoc(xmldoc);
2840         return hr;
2841     }
2842
2843     return hr;
2844 }
2845
2846 IUnknown* create_domdoc( xmlNodePtr document )
2847 {
2848     void* pObj = NULL;
2849     HRESULT hr;
2850
2851     TRACE("(%p)\n", document);
2852
2853     hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
2854     if (FAILED(hr))
2855         return NULL;
2856
2857     return pObj;
2858 }
2859
2860 #else
2861
2862 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
2863 {
2864     MESSAGE("This program tried to use a DOMDocument object, but\n"
2865             "libxml2 support was not present at compile time.\n");
2866     return E_NOTIMPL;
2867 }
2868
2869 #endif