msxml3: Move attach_xmlnode.c to domdoc.c.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winnls.h"
32 #include "ole2.h"
33 #include "msxml2.h"
34 #include "wininet.h"
35 #include "winreg.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "objsafe.h"
39 #include "dispex.h"
40
41 #include "wine/debug.h"
42 #include "wine/list.h"
43
44 #include "msxml_private.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
47
48 #ifdef HAVE_LIBXML2
49
50 static const WCHAR SZ_PROPERTY_SELECTION_LANGUAGE[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
51 static const WCHAR SZ_VALUE_XPATH[] = {'X','P','a','t','h',0};
52 static const WCHAR SZ_VALUE_XSLPATTERN[] = {'X','S','L','P','a','t','t','e','r','n',0};
53
54 typedef struct _domdoc
55 {
56     const struct IXMLDOMDocument2Vtbl *lpVtbl;
57     const struct IPersistStreamVtbl   *lpvtblIPersistStream;
58     const struct IObjectWithSiteVtbl  *lpvtblIObjectWithSite;
59     const struct IObjectSafetyVtbl    *lpvtblIObjectSafety;
60     LONG ref;
61     VARIANT_BOOL async;
62     VARIANT_BOOL validating;
63     VARIANT_BOOL resolving;
64     VARIANT_BOOL preserving;
65     BOOL bUseXPath;
66     IUnknown *node_unk;
67     IXMLDOMNode *node;
68     IXMLDOMSchemaCollection *schema;
69     bsc_t *bsc;
70     HRESULT error;
71
72     /* IPersistStream */
73     IStream *stream;
74
75     /* IObjectWithSite*/
76     IUnknown *site;
77
78     /* IObjectSafety */
79     DWORD safeopt;
80
81     /* IDispatchEx */
82     DispatchEx dispex;
83 } domdoc;
84
85 /*
86   In native windows, the whole lifetime management of XMLDOMNodes is
87   managed automatically using reference counts. Wine emulates that by
88   maintaining a reference count to the document that is increased for
89   each IXMLDOMNode pointer passed out for this document. If all these
90   pointers are gone, the document is unreachable and gets freed, that
91   is, all nodes in the tree of the document get freed.
92
93   You are able to create nodes that are associated to a document (in
94   fact, in msxml's XMLDOM model, all nodes are associated to a document),
95   but not in the tree of that document, for example using the createFoo
96   functions from IXMLDOMDocument. These nodes do not get cleaned up
97   by libxml, so we have to do it ourselves.
98
99   To catch these nodes, a list of "orphan nodes" is introduced.
100   It contains pointers to all roots of node trees that are
101   associated with the document without being part of the document
102   tree. All nodes with parent==NULL (except for the document root nodes)
103   should be in the orphan node list of their document. All orphan nodes
104   get freed together with the document itself.
105  */
106
107 typedef struct _xmldoc_priv {
108     LONG refs;
109     struct list orphans;
110 } xmldoc_priv;
111
112 typedef struct _orphan_entry {
113     struct list entry;
114     xmlNode * node;
115 } orphan_entry;
116
117 static inline xmldoc_priv * priv_from_xmlDocPtr(xmlDocPtr doc)
118 {
119     return doc->_private;
120 }
121
122 static xmldoc_priv * create_priv(void)
123 {
124     xmldoc_priv *priv;
125     priv = HeapAlloc( GetProcessHeap(), 0, sizeof (*priv) );
126
127     if(priv)
128     {
129         priv->refs = 0;
130         list_init( &priv->orphans );
131     }
132
133     return priv;
134 }
135
136 static xmlDocPtr doparse( char *ptr, int len )
137 {
138 #ifdef HAVE_XMLREADMEMORY
139     /*
140      * use xmlReadMemory if possible so we can suppress
141      * writing errors to stderr
142      */
143     return xmlReadMemory( ptr, len, NULL, NULL,
144                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS );
145 #else
146     return xmlParseMemory( ptr, len );
147 #endif
148 }
149
150 LONG xmldoc_add_ref(xmlDocPtr doc)
151 {
152     LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
153     TRACE("%d\n", ref);
154     return ref;
155 }
156
157 LONG xmldoc_release(xmlDocPtr doc)
158 {
159     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
160     LONG ref = InterlockedDecrement(&priv->refs);
161     TRACE("%d\n", ref);
162     if(ref == 0)
163     {
164         orphan_entry *orphan, *orphan2;
165         TRACE("freeing docptr %p\n", doc);
166
167         LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
168         {
169             xmlFreeNode( orphan->node );
170             HeapFree( GetProcessHeap(), 0, orphan );
171         }
172         HeapFree(GetProcessHeap(), 0, doc->_private);
173
174         xmlFreeDoc(doc);
175     }
176
177     return ref;
178 }
179
180 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
181 {
182     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
183     orphan_entry *entry;
184
185     entry = HeapAlloc( GetProcessHeap(), 0, sizeof (*entry) );
186     if(!entry)
187         return E_OUTOFMEMORY;
188
189     entry->node = node;
190     list_add_head( &priv->orphans, &entry->entry );
191     return S_OK;
192 }
193
194 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
195 {
196     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
197     orphan_entry *entry, *entry2;
198
199     LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
200     {
201         if( entry->node == node )
202         {
203             list_remove( &entry->entry );
204             HeapFree( GetProcessHeap(), 0, entry );
205             return S_OK;
206         }
207     }
208
209     return S_FALSE;
210 }
211
212 static void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xml )
213 {
214     xmlnode *This = impl_from_IXMLDOMNode( node );
215
216     if(This->node)
217         xmldoc_release(This->node->doc);
218
219     This->node = xml;
220     if(This->node)
221         xmldoc_add_ref(This->node->doc);
222
223     return;
224 }
225
226 static inline domdoc *impl_from_IXMLDOMDocument2( IXMLDOMDocument2 *iface )
227 {
228     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
229 }
230
231 static inline xmlDocPtr get_doc( domdoc *This )
232 {
233     return (xmlDocPtr) xmlNodePtr_from_domnode( This->node, XML_DOCUMENT_NODE );
234 }
235
236 static inline domdoc *impl_from_IPersistStream(IPersistStream *iface)
237 {
238     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIPersistStream));
239 }
240
241 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
242 {
243     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectWithSite));
244 }
245
246 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
247 {
248     return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectSafety));
249 }
250
251
252 /************************************************************************
253  * xmldoc implementation of IPersistStream.
254  */
255 static HRESULT WINAPI xmldoc_IPersistStream_QueryInterface(
256     IPersistStream *iface, REFIID riid, LPVOID *ppvObj)
257 {
258     domdoc *this = impl_from_IPersistStream(iface);
259     return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
260 }
261
262 static ULONG WINAPI xmldoc_IPersistStream_AddRef(
263     IPersistStream *iface)
264 {
265     domdoc *this = impl_from_IPersistStream(iface);
266     return IXMLDocument_AddRef((IXMLDocument *)this);
267 }
268
269 static ULONG WINAPI xmldoc_IPersistStream_Release(
270     IPersistStream *iface)
271 {
272     domdoc *this = impl_from_IPersistStream(iface);
273     return IXMLDocument_Release((IXMLDocument *)this);
274 }
275
276 static HRESULT WINAPI xmldoc_IPersistStream_GetClassID(
277     IPersistStream *iface, CLSID *classid)
278 {
279     TRACE("(%p,%p): stub!\n", iface, classid);
280
281     if(!classid)
282         return E_POINTER;
283
284     *classid = CLSID_DOMDocument2;
285
286     return S_OK;
287 }
288
289 static HRESULT WINAPI xmldoc_IPersistStream_IsDirty(
290     IPersistStream *iface)
291 {
292     domdoc *This = impl_from_IPersistStream(iface);
293
294     FIXME("(%p->%p): stub!\n", iface, This);
295
296     return S_FALSE;
297 }
298
299 static HRESULT WINAPI xmldoc_IPersistStream_Load(
300     IPersistStream *iface, LPSTREAM pStm)
301 {
302     domdoc *This = impl_from_IPersistStream(iface);
303     HRESULT hr;
304     HGLOBAL hglobal;
305     DWORD read, written, len;
306     BYTE buf[4096];
307     char *ptr;
308     xmlDocPtr xmldoc = NULL;
309
310     TRACE("(%p, %p)\n", iface, pStm);
311
312     if (!pStm)
313         return E_INVALIDARG;
314
315     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
316     if (FAILED(hr))
317         return hr;
318
319     do
320     {
321         IStream_Read(pStm, buf, sizeof(buf), &read);
322         hr = IStream_Write(This->stream, buf, read, &written);
323     } while(SUCCEEDED(hr) && written != 0 && read != 0);
324
325     if (FAILED(hr))
326     {
327         ERR("Failed to copy stream\n");
328         return hr;
329     }
330
331     hr = GetHGlobalFromStream(This->stream, &hglobal);
332     if (FAILED(hr))
333         return hr;
334
335     len = GlobalSize(hglobal);
336     ptr = GlobalLock(hglobal);
337     if (len != 0)
338         xmldoc = parse_xml(ptr, len);
339     GlobalUnlock(hglobal);
340
341     if (!xmldoc)
342     {
343         ERR("Failed to parse xml\n");
344         return E_FAIL;
345     }
346
347     xmldoc->_private = create_priv();
348     attach_xmlnode( This->node, (xmlNodePtr)xmldoc );
349
350     return S_OK;
351 }
352
353 static HRESULT WINAPI xmldoc_IPersistStream_Save(
354     IPersistStream *iface, LPSTREAM pStm, BOOL fClearDirty)
355 {
356     FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty);
357     return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI xmldoc_IPersistStream_GetSizeMax(
361     IPersistStream *iface, ULARGE_INTEGER *pcbSize)
362 {
363     TRACE("(%p, %p): stub!\n", iface, pcbSize);
364     return E_NOTIMPL;
365 }
366
367 static const IPersistStreamVtbl xmldoc_IPersistStream_VTable =
368 {
369     xmldoc_IPersistStream_QueryInterface,
370     xmldoc_IPersistStream_AddRef,
371     xmldoc_IPersistStream_Release,
372     xmldoc_IPersistStream_GetClassID,
373     xmldoc_IPersistStream_IsDirty,
374     xmldoc_IPersistStream_Load,
375     xmldoc_IPersistStream_Save,
376     xmldoc_IPersistStream_GetSizeMax,
377 };
378
379 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument2 *iface, REFIID riid, void** ppvObject )
380 {
381     domdoc *This = impl_from_IXMLDOMDocument2( iface );
382
383     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
384
385     *ppvObject = NULL;
386
387     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
388          IsEqualGUID( riid, &IID_IDispatch ) ||
389          IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
390          IsEqualGUID( riid, &IID_IXMLDOMDocument2 ) )
391     {
392         *ppvObject = iface;
393     }
394     else if ( IsEqualGUID( riid, &IID_IXMLDOMNode ) )
395     {
396         return IUnknown_QueryInterface(This->node_unk, riid, ppvObject);
397     }
398     else if (IsEqualGUID(&IID_IPersistStream, riid))
399     {
400         *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
401     }
402     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
403     {
404         *ppvObject = (IObjectWithSite*)&(This->lpvtblIObjectWithSite);
405     }
406     else if(dispex_query_interface(&This->dispex, riid, ppvObject))
407     {
408         return *ppvObject ? S_OK : E_NOINTERFACE;
409     }
410     else if(IsEqualGUID(&IID_IRunnableObject, riid))
411     {
412         TRACE("IID_IRunnableObject not supported returning NULL\n");
413         return E_NOINTERFACE;
414     }
415     else
416     {
417         FIXME("interface %s not implemented\n", debugstr_guid(riid));
418         return E_NOINTERFACE;
419     }
420
421     IXMLDOMDocument_AddRef( iface );
422
423     return S_OK;
424 }
425
426
427 static ULONG WINAPI domdoc_AddRef(
428      IXMLDOMDocument2 *iface )
429 {
430     domdoc *This = impl_from_IXMLDOMDocument2( iface );
431     TRACE("%p\n", This );
432     return InterlockedIncrement( &This->ref );
433 }
434
435
436 static ULONG WINAPI domdoc_Release(
437      IXMLDOMDocument2 *iface )
438 {
439     domdoc *This = impl_from_IXMLDOMDocument2( iface );
440     LONG ref;
441
442     TRACE("%p\n", This );
443
444     ref = InterlockedDecrement( &This->ref );
445     if ( ref == 0 )
446     {
447         if(This->bsc)
448             detach_bsc(This->bsc);
449
450         if (This->site)
451             IUnknown_Release( This->site );
452         IUnknown_Release( This->node_unk );
453         if(This->schema) IXMLDOMSchemaCollection_Release( This->schema );
454         if (This->stream) IStream_Release(This->stream);
455         HeapFree( GetProcessHeap(), 0, This );
456     }
457
458     return ref;
459 }
460
461 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument2 *iface, UINT* pctinfo )
462 {
463     domdoc *This = impl_from_IXMLDOMDocument2( iface );
464
465     TRACE("(%p)->(%p)\n", This, pctinfo);
466
467     *pctinfo = 1;
468
469     return S_OK;
470 }
471
472 static HRESULT WINAPI domdoc_GetTypeInfo(
473     IXMLDOMDocument2 *iface,
474     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
475 {
476     domdoc *This = impl_from_IXMLDOMDocument2( iface );
477     HRESULT hr;
478
479     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
480
481     hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
482
483     return hr;
484 }
485
486 static HRESULT WINAPI domdoc_GetIDsOfNames(
487     IXMLDOMDocument2 *iface,
488     REFIID riid,
489     LPOLESTR* rgszNames,
490     UINT cNames,
491     LCID lcid,
492     DISPID* rgDispId)
493 {
494     domdoc *This = impl_from_IXMLDOMDocument2( iface );
495     ITypeInfo *typeinfo;
496     HRESULT hr;
497
498     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
499           lcid, rgDispId);
500
501     if(!rgszNames || cNames == 0 || !rgDispId)
502         return E_INVALIDARG;
503
504     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
505     if(SUCCEEDED(hr))
506     {
507         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
508         ITypeInfo_Release(typeinfo);
509     }
510
511     return hr;
512 }
513
514
515 static HRESULT WINAPI domdoc_Invoke(
516     IXMLDOMDocument2 *iface,
517     DISPID dispIdMember,
518     REFIID riid,
519     LCID lcid,
520     WORD wFlags,
521     DISPPARAMS* pDispParams,
522     VARIANT* pVarResult,
523     EXCEPINFO* pExcepInfo,
524     UINT* puArgErr)
525 {
526     domdoc *This = impl_from_IXMLDOMDocument2( iface );
527     ITypeInfo *typeinfo;
528     HRESULT hr;
529
530     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
531           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
532
533     hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
534     if(SUCCEEDED(hr))
535     {
536         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
537                 pVarResult, pExcepInfo, puArgErr);
538         ITypeInfo_Release(typeinfo);
539     }
540
541     return hr;
542 }
543
544
545 static HRESULT WINAPI domdoc_get_nodeName(
546     IXMLDOMDocument2 *iface,
547     BSTR* name )
548 {
549     domdoc *This = impl_from_IXMLDOMDocument2( iface );
550     return IXMLDOMNode_get_nodeName( This->node, name );
551 }
552
553
554 static HRESULT WINAPI domdoc_get_nodeValue(
555     IXMLDOMDocument2 *iface,
556     VARIANT* value )
557 {
558     domdoc *This = impl_from_IXMLDOMDocument2( iface );
559     return IXMLDOMNode_get_nodeValue( This->node, value );
560 }
561
562
563 static HRESULT WINAPI domdoc_put_nodeValue(
564     IXMLDOMDocument2 *iface,
565     VARIANT value)
566 {
567     domdoc *This = impl_from_IXMLDOMDocument2( iface );
568     return IXMLDOMNode_put_nodeValue( This->node, value );
569 }
570
571
572 static HRESULT WINAPI domdoc_get_nodeType(
573     IXMLDOMDocument2 *iface,
574     DOMNodeType* type )
575 {
576     domdoc *This = impl_from_IXMLDOMDocument2( iface );
577     return IXMLDOMNode_get_nodeType( This->node, type );
578 }
579
580
581 static HRESULT WINAPI domdoc_get_parentNode(
582     IXMLDOMDocument2 *iface,
583     IXMLDOMNode** parent )
584 {
585     domdoc *This = impl_from_IXMLDOMDocument2( iface );
586     return IXMLDOMNode_get_parentNode( This->node, parent );
587 }
588
589
590 static HRESULT WINAPI domdoc_get_childNodes(
591     IXMLDOMDocument2 *iface,
592     IXMLDOMNodeList** childList )
593 {
594     domdoc *This = impl_from_IXMLDOMDocument2( iface );
595     return IXMLDOMNode_get_childNodes( This->node, childList );
596 }
597
598
599 static HRESULT WINAPI domdoc_get_firstChild(
600     IXMLDOMDocument2 *iface,
601     IXMLDOMNode** firstChild )
602 {
603     domdoc *This = impl_from_IXMLDOMDocument2( iface );
604     return IXMLDOMNode_get_firstChild( This->node, firstChild );
605 }
606
607
608 static HRESULT WINAPI domdoc_get_lastChild(
609     IXMLDOMDocument2 *iface,
610     IXMLDOMNode** lastChild )
611 {
612     domdoc *This = impl_from_IXMLDOMDocument2( iface );
613     return IXMLDOMNode_get_lastChild( This->node, lastChild );
614 }
615
616
617 static HRESULT WINAPI domdoc_get_previousSibling(
618     IXMLDOMDocument2 *iface,
619     IXMLDOMNode** previousSibling )
620 {
621     domdoc *This = impl_from_IXMLDOMDocument2( iface );
622     return IXMLDOMNode_get_previousSibling( This->node, previousSibling );
623 }
624
625
626 static HRESULT WINAPI domdoc_get_nextSibling(
627     IXMLDOMDocument2 *iface,
628     IXMLDOMNode** nextSibling )
629 {
630     domdoc *This = impl_from_IXMLDOMDocument2( iface );
631     return IXMLDOMNode_get_nextSibling( This->node, nextSibling );
632 }
633
634
635 static HRESULT WINAPI domdoc_get_attributes(
636     IXMLDOMDocument2 *iface,
637     IXMLDOMNamedNodeMap** attributeMap )
638 {
639     domdoc *This = impl_from_IXMLDOMDocument2( iface );
640     return IXMLDOMNode_get_attributes( This->node, attributeMap );
641 }
642
643
644 static HRESULT WINAPI domdoc_insertBefore(
645     IXMLDOMDocument2 *iface,
646     IXMLDOMNode* newChild,
647     VARIANT refChild,
648     IXMLDOMNode** outNewChild )
649 {
650     domdoc *This = impl_from_IXMLDOMDocument2( iface );
651     return IXMLDOMNode_insertBefore( This->node, newChild, refChild, outNewChild );
652 }
653
654
655 static HRESULT WINAPI domdoc_replaceChild(
656     IXMLDOMDocument2 *iface,
657     IXMLDOMNode* newChild,
658     IXMLDOMNode* oldChild,
659     IXMLDOMNode** outOldChild)
660 {
661     domdoc *This = impl_from_IXMLDOMDocument2( iface );
662     return IXMLDOMNode_replaceChild( This->node, newChild, oldChild, outOldChild );
663 }
664
665
666 static HRESULT WINAPI domdoc_removeChild(
667     IXMLDOMDocument2 *iface,
668     IXMLDOMNode* childNode,
669     IXMLDOMNode** oldChild)
670 {
671     domdoc *This = impl_from_IXMLDOMDocument2( iface );
672     return IXMLDOMNode_removeChild( This->node, childNode, oldChild );
673 }
674
675
676 static HRESULT WINAPI domdoc_appendChild(
677     IXMLDOMDocument2 *iface,
678     IXMLDOMNode* newChild,
679     IXMLDOMNode** outNewChild)
680 {
681     domdoc *This = impl_from_IXMLDOMDocument2( iface );
682     return IXMLDOMNode_appendChild( This->node, newChild, outNewChild );
683 }
684
685
686 static HRESULT WINAPI domdoc_hasChildNodes(
687     IXMLDOMDocument2 *iface,
688     VARIANT_BOOL* hasChild)
689 {
690     domdoc *This = impl_from_IXMLDOMDocument2( iface );
691     return IXMLDOMNode_hasChildNodes( This->node, hasChild );
692 }
693
694
695 static HRESULT WINAPI domdoc_get_ownerDocument(
696     IXMLDOMDocument2 *iface,
697     IXMLDOMDocument** DOMDocument)
698 {
699     domdoc *This = impl_from_IXMLDOMDocument2( iface );
700     return IXMLDOMNode_get_ownerDocument( This->node, DOMDocument );
701 }
702
703
704 static HRESULT WINAPI domdoc_cloneNode(
705     IXMLDOMDocument2 *iface,
706     VARIANT_BOOL deep,
707     IXMLDOMNode** cloneRoot)
708 {
709     domdoc *This = impl_from_IXMLDOMDocument2( iface );
710     return IXMLDOMNode_cloneNode( This->node, deep, cloneRoot );
711 }
712
713
714 static HRESULT WINAPI domdoc_get_nodeTypeString(
715     IXMLDOMDocument2 *iface,
716     BSTR* nodeType )
717 {
718     domdoc *This = impl_from_IXMLDOMDocument2( iface );
719     return IXMLDOMNode_get_nodeTypeString( This->node, nodeType );
720 }
721
722
723 static HRESULT WINAPI domdoc_get_text(
724     IXMLDOMDocument2 *iface,
725     BSTR* text )
726 {
727     domdoc *This = impl_from_IXMLDOMDocument2( iface );
728     return IXMLDOMNode_get_text( This->node, text );
729 }
730
731
732 static HRESULT WINAPI domdoc_put_text(
733     IXMLDOMDocument2 *iface,
734     BSTR text )
735 {
736     domdoc *This = impl_from_IXMLDOMDocument2( iface );
737     return IXMLDOMNode_put_text( This->node, text );
738 }
739
740
741 static HRESULT WINAPI domdoc_get_specified(
742     IXMLDOMDocument2 *iface,
743     VARIANT_BOOL* isSpecified )
744 {
745     domdoc *This = impl_from_IXMLDOMDocument2( iface );
746     return IXMLDOMNode_get_specified( This->node, isSpecified );
747 }
748
749
750 static HRESULT WINAPI domdoc_get_definition(
751     IXMLDOMDocument2 *iface,
752     IXMLDOMNode** definitionNode )
753 {
754     domdoc *This = impl_from_IXMLDOMDocument2( iface );
755     return IXMLDOMNode_get_definition( This->node, definitionNode );
756 }
757
758
759 static HRESULT WINAPI domdoc_get_nodeTypedValue(
760     IXMLDOMDocument2 *iface,
761     VARIANT* typedValue )
762 {
763     domdoc *This = impl_from_IXMLDOMDocument2( iface );
764     return IXMLDOMNode_get_nodeTypedValue( This->node, typedValue );
765 }
766
767 static HRESULT WINAPI domdoc_put_nodeTypedValue(
768     IXMLDOMDocument2 *iface,
769     VARIANT typedValue )
770 {
771     domdoc *This = impl_from_IXMLDOMDocument2( iface );
772     return IXMLDOMNode_put_nodeTypedValue( This->node, typedValue );
773 }
774
775
776 static HRESULT WINAPI domdoc_get_dataType(
777     IXMLDOMDocument2 *iface,
778     VARIANT* dataTypeName )
779 {
780     domdoc *This = impl_from_IXMLDOMDocument2( iface );
781     return IXMLDOMNode_get_dataType( This->node, dataTypeName );
782 }
783
784
785 static HRESULT WINAPI domdoc_put_dataType(
786     IXMLDOMDocument2 *iface,
787     BSTR dataTypeName )
788 {
789     domdoc *This = impl_from_IXMLDOMDocument2( iface );
790     return IXMLDOMNode_put_dataType( This->node, dataTypeName );
791 }
792
793
794 static HRESULT WINAPI domdoc_get_xml(
795     IXMLDOMDocument2 *iface,
796     BSTR* xmlString )
797 {
798     domdoc *This = impl_from_IXMLDOMDocument2( iface );
799     return IXMLDOMNode_get_xml( This->node, xmlString );
800 }
801
802
803 static HRESULT WINAPI domdoc_transformNode(
804     IXMLDOMDocument2 *iface,
805     IXMLDOMNode* styleSheet,
806     BSTR* xmlString )
807 {
808     domdoc *This = impl_from_IXMLDOMDocument2( iface );
809     return IXMLDOMNode_transformNode( This->node, styleSheet, xmlString );
810 }
811
812
813 static HRESULT WINAPI domdoc_selectNodes(
814     IXMLDOMDocument2 *iface,
815     BSTR queryString,
816     IXMLDOMNodeList** resultList )
817 {
818     domdoc *This = impl_from_IXMLDOMDocument2( iface );
819     return IXMLDOMNode_selectNodes( This->node, queryString, resultList );
820 }
821
822
823 static HRESULT WINAPI domdoc_selectSingleNode(
824     IXMLDOMDocument2 *iface,
825     BSTR queryString,
826     IXMLDOMNode** resultNode )
827 {
828     domdoc *This = impl_from_IXMLDOMDocument2( iface );
829     return IXMLDOMNode_selectSingleNode( This->node, queryString, resultNode );
830 }
831
832
833 static HRESULT WINAPI domdoc_get_parsed(
834     IXMLDOMDocument2 *iface,
835     VARIANT_BOOL* isParsed )
836 {
837     domdoc *This = impl_from_IXMLDOMDocument2( iface );
838     return IXMLDOMNode_get_parsed( This->node, isParsed );
839 }
840
841
842 static HRESULT WINAPI domdoc_get_namespaceURI(
843     IXMLDOMDocument2 *iface,
844     BSTR* namespaceURI )
845 {
846     domdoc *This = impl_from_IXMLDOMDocument2( iface );
847     return IXMLDOMNode_get_namespaceURI( This->node, namespaceURI );
848 }
849
850
851 static HRESULT WINAPI domdoc_get_prefix(
852     IXMLDOMDocument2 *iface,
853     BSTR* prefixString )
854 {
855     domdoc *This = impl_from_IXMLDOMDocument2( iface );
856     return IXMLDOMNode_get_prefix( This->node, prefixString );
857 }
858
859
860 static HRESULT WINAPI domdoc_get_baseName(
861     IXMLDOMDocument2 *iface,
862     BSTR* nameString )
863 {
864     domdoc *This = impl_from_IXMLDOMDocument2( iface );
865     return IXMLDOMNode_get_baseName( This->node, nameString );
866 }
867
868
869 static HRESULT WINAPI domdoc_transformNodeToObject(
870     IXMLDOMDocument2 *iface,
871     IXMLDOMNode* stylesheet,
872     VARIANT outputObject)
873 {
874     domdoc *This = impl_from_IXMLDOMDocument2( iface );
875     return IXMLDOMNode_transformNodeToObject( This->node, stylesheet, outputObject );
876 }
877
878
879 static HRESULT WINAPI domdoc_get_doctype(
880     IXMLDOMDocument2 *iface,
881     IXMLDOMDocumentType** documentType )
882 {
883     FIXME("\n");
884     return E_NOTIMPL;
885 }
886
887
888 static HRESULT WINAPI domdoc_get_implementation(
889     IXMLDOMDocument2 *iface,
890     IXMLDOMImplementation** impl )
891 {
892     if(!impl)
893         return E_INVALIDARG;
894
895     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
896
897     return S_OK;
898 }
899
900 static HRESULT WINAPI domdoc_get_documentElement(
901     IXMLDOMDocument2 *iface,
902     IXMLDOMElement** DOMElement )
903 {
904     domdoc *This = impl_from_IXMLDOMDocument2( iface );
905     xmlDocPtr xmldoc = NULL;
906     xmlNodePtr root = NULL;
907     IXMLDOMNode *element_node;
908     HRESULT hr;
909
910     TRACE("%p %p\n", This, This->node);
911
912     if(!DOMElement)
913         return E_INVALIDARG;
914
915     *DOMElement = NULL;
916
917     xmldoc = get_doc( This );
918
919     root = xmlDocGetRootElement( xmldoc );
920     if ( !root )
921         return S_FALSE;
922
923     element_node = create_node( root );
924     if(!element_node) return S_FALSE;
925
926     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (LPVOID*)DOMElement);
927     IXMLDOMNode_Release(element_node);
928
929     return hr;
930 }
931
932
933 static HRESULT WINAPI domdoc_put_documentElement(
934     IXMLDOMDocument2 *iface,
935     IXMLDOMElement* DOMElement )
936 {
937     domdoc *This = impl_from_IXMLDOMDocument2( iface );
938     IXMLDOMNode *elementNode;
939     xmlNodePtr oldRoot;
940     xmlnode *xmlNode;
941     HRESULT hr;
942
943     TRACE("(%p)->(%p)\n", This, DOMElement);
944
945     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
946     if(FAILED(hr))
947         return hr;
948
949     xmlNode = impl_from_IXMLDOMNode( elementNode );
950
951     if(!xmlNode->node->parent)
952         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
953             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
954
955     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
956     IXMLDOMNode_Release( elementNode );
957
958     if(oldRoot)
959         xmldoc_add_orphan(oldRoot->doc, oldRoot);
960
961     return S_OK;
962 }
963
964
965 static HRESULT WINAPI domdoc_createElement(
966     IXMLDOMDocument2 *iface,
967     BSTR tagname,
968     IXMLDOMElement** element )
969 {
970     xmlNodePtr xmlnode;
971     domdoc *This = impl_from_IXMLDOMDocument2( iface );
972     xmlChar *xml_name;
973     IUnknown *elem_unk;
974     HRESULT hr;
975
976     TRACE("%p->(%s,%p)\n", iface, debugstr_w(tagname), element);
977
978     xml_name = xmlChar_from_wchar((WCHAR*)tagname);
979     xmlnode = xmlNewDocNode(get_doc(This), NULL, xml_name, NULL);
980     xmldoc_add_orphan(xmlnode->doc, xmlnode);
981
982     TRACE("created xmlptr %p\n", xmlnode);
983     elem_unk = create_element(xmlnode, NULL);
984     HeapFree(GetProcessHeap(), 0, xml_name);
985
986     hr = IUnknown_QueryInterface(elem_unk, &IID_IXMLDOMElement, (void **)element);
987     IUnknown_Release(elem_unk);
988     TRACE("returning %p\n", *element);
989     return hr;
990 }
991
992
993 static HRESULT WINAPI domdoc_createDocumentFragment(
994     IXMLDOMDocument2 *iface,
995     IXMLDOMDocumentFragment** docFrag )
996 {
997     domdoc *This = impl_from_IXMLDOMDocument2( iface );
998     xmlNodePtr xmlnode;
999
1000     TRACE("%p\n", iface);
1001
1002     if(!docFrag)
1003         return E_INVALIDARG;
1004
1005     *docFrag = NULL;
1006
1007     xmlnode = xmlNewDocFragment(get_doc( This ) );
1008
1009     if(!xmlnode)
1010         return E_FAIL;
1011
1012     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1013     *docFrag = (IXMLDOMDocumentFragment*)create_doc_fragment(xmlnode);
1014
1015     return S_OK;
1016 }
1017
1018
1019 static HRESULT WINAPI domdoc_createTextNode(
1020     IXMLDOMDocument2 *iface,
1021     BSTR data,
1022     IXMLDOMText** text )
1023 {
1024     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1025     xmlNodePtr xmlnode;
1026     xmlChar *xml_content;
1027
1028     TRACE("%p->(%s %p)\n", iface, debugstr_w(data), text);
1029
1030     if(!text)
1031         return E_INVALIDARG;
1032
1033     *text = NULL;
1034
1035     xml_content = xmlChar_from_wchar((WCHAR*)data);
1036     xmlnode = xmlNewText(xml_content);
1037     HeapFree(GetProcessHeap(), 0, xml_content);
1038
1039     if(!xmlnode)
1040         return E_FAIL;
1041
1042     xmlnode->doc = get_doc( This );
1043     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1044
1045     *text = (IXMLDOMText*)create_text(xmlnode);
1046
1047     return S_OK;
1048 }
1049
1050
1051 static HRESULT WINAPI domdoc_createComment(
1052     IXMLDOMDocument2 *iface,
1053     BSTR data,
1054     IXMLDOMComment** comment )
1055 {
1056     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1057     xmlNodePtr xmlnode;
1058     xmlChar *xml_content;
1059
1060     TRACE("%p->(%s %p)\n", iface, debugstr_w(data), comment);
1061
1062     if(!comment)
1063         return E_INVALIDARG;
1064
1065     *comment = NULL;
1066
1067     xml_content = xmlChar_from_wchar((WCHAR*)data);
1068     xmlnode = xmlNewComment(xml_content);
1069     HeapFree(GetProcessHeap(), 0, xml_content);
1070
1071     if(!xmlnode)
1072         return E_FAIL;
1073
1074     xmlnode->doc = get_doc( This );
1075     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1076
1077     *comment = (IXMLDOMComment*)create_comment(xmlnode);
1078
1079     return S_OK;
1080 }
1081
1082
1083 static HRESULT WINAPI domdoc_createCDATASection(
1084     IXMLDOMDocument2 *iface,
1085     BSTR data,
1086     IXMLDOMCDATASection** cdata )
1087 {
1088     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1089     xmlNodePtr xmlnode;
1090     xmlChar *xml_content;
1091
1092     TRACE("%p->(%s %p)\n", iface, debugstr_w(data), cdata);
1093
1094     if(!cdata)
1095         return E_INVALIDARG;
1096
1097     *cdata = NULL;
1098
1099     xml_content = xmlChar_from_wchar((WCHAR*)data);
1100     xmlnode = xmlNewCDataBlock(get_doc( This ), xml_content, strlen( (char*)xml_content) );
1101     HeapFree(GetProcessHeap(), 0, xml_content);
1102
1103     if(!xmlnode)
1104         return E_FAIL;
1105
1106     xmlnode->doc = get_doc( This );
1107     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1108
1109     *cdata = (IXMLDOMCDATASection*)create_cdata(xmlnode);
1110
1111     return S_OK;
1112 }
1113
1114
1115 static HRESULT WINAPI domdoc_createProcessingInstruction(
1116     IXMLDOMDocument2 *iface,
1117     BSTR target,
1118     BSTR data,
1119     IXMLDOMProcessingInstruction** pi )
1120 {
1121 #ifdef HAVE_XMLNEWDOCPI
1122     xmlNodePtr xmlnode;
1123     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1124     xmlChar *xml_target, *xml_content;
1125
1126     TRACE("%p->(%s %s %p)\n", iface, debugstr_w(target), debugstr_w(data), pi);
1127
1128     if(!pi)
1129         return E_INVALIDARG;
1130
1131     if(!target || lstrlenW(target) == 0)
1132         return E_FAIL;
1133
1134     xml_target = xmlChar_from_wchar((WCHAR*)target);
1135     xml_content = xmlChar_from_wchar((WCHAR*)data);
1136
1137     xmlnode = xmlNewDocPI(get_doc(This), xml_target, xml_content);
1138     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1139     TRACE("created xmlptr %p\n", xmlnode);
1140     *pi = (IXMLDOMProcessingInstruction*)create_pi(xmlnode);
1141
1142     HeapFree(GetProcessHeap(), 0, xml_content);
1143     HeapFree(GetProcessHeap(), 0, xml_target);
1144
1145     return S_OK;
1146 #else
1147     FIXME("Libxml 2.6.15 or greater required.\n");
1148     return E_NOTIMPL;
1149 #endif
1150 }
1151
1152
1153 static HRESULT WINAPI domdoc_createAttribute(
1154     IXMLDOMDocument2 *iface,
1155     BSTR name,
1156     IXMLDOMAttribute** attribute )
1157 {
1158     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1159     xmlNodePtr xmlnode;
1160     xmlChar *xml_name;
1161
1162     TRACE("%p->(%s %p)\n", iface, debugstr_w(name), attribute);
1163
1164     if(!attribute)
1165         return E_INVALIDARG;
1166
1167     *attribute = NULL;
1168
1169     xml_name = xmlChar_from_wchar((WCHAR*)name);
1170     xmlnode = (xmlNode *)xmlNewProp(NULL, xml_name, NULL);
1171     HeapFree(GetProcessHeap(), 0, xml_name);
1172
1173     if(!xmlnode)
1174         return E_FAIL;
1175
1176     xmlnode->doc = get_doc( This );
1177     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1178
1179     *attribute = (IXMLDOMAttribute*)create_attribute(xmlnode);
1180
1181     return S_OK;
1182 }
1183
1184
1185 static HRESULT WINAPI domdoc_createEntityReference(
1186     IXMLDOMDocument2 *iface,
1187     BSTR name,
1188     IXMLDOMEntityReference** entityRef )
1189 {
1190     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1191     xmlNodePtr xmlnode;
1192     xmlChar *xml_name;
1193
1194     TRACE("%p\n", iface);
1195
1196     if(!entityRef)
1197         return E_INVALIDARG;
1198
1199     *entityRef = NULL;
1200
1201     xml_name = xmlChar_from_wchar((WCHAR*)name);
1202     xmlnode = xmlNewReference(get_doc( This ), xml_name );
1203     HeapFree(GetProcessHeap(), 0, xml_name);
1204
1205     if(!xmlnode)
1206         return E_FAIL;
1207
1208     xmlnode->doc = get_doc( This );
1209     xmldoc_add_orphan(xmlnode->doc, xmlnode);
1210
1211     *entityRef = (IXMLDOMEntityReference*)create_doc_entity_ref(xmlnode);
1212
1213     return S_OK;
1214 }
1215
1216
1217 static HRESULT WINAPI domdoc_getElementsByTagName(
1218     IXMLDOMDocument2 *iface,
1219     BSTR tagName,
1220     IXMLDOMNodeList** resultList )
1221 {
1222     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1223     LPWSTR szPattern;
1224     HRESULT hr;
1225     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1226
1227     szPattern = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(2+lstrlenW(tagName)+1));
1228     szPattern[0] = szPattern[1] = '/';
1229     lstrcpyW(szPattern + 2, tagName);
1230
1231     hr = queryresult_create((xmlNodePtr)get_doc(This), szPattern, resultList);
1232     HeapFree(GetProcessHeap(), 0, szPattern);
1233
1234     return hr;
1235 }
1236
1237 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1238 {
1239     VARIANT tmp;
1240     HRESULT hr;
1241
1242     VariantInit(&tmp);
1243     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1244     if(FAILED(hr))
1245         return E_INVALIDARG;
1246
1247     *type = V_I4(&tmp);
1248
1249     return S_OK;
1250 }
1251
1252 static HRESULT WINAPI domdoc_createNode(
1253     IXMLDOMDocument2 *iface,
1254     VARIANT Type,
1255     BSTR name,
1256     BSTR namespaceURI,
1257     IXMLDOMNode** node )
1258 {
1259     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1260     DOMNodeType node_type;
1261     xmlNodePtr xmlnode = NULL;
1262     xmlChar *xml_name;
1263     HRESULT hr;
1264
1265     TRACE("(%p)->(type,%s,%s,%p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1266
1267     hr = get_node_type(Type, &node_type);
1268     if(FAILED(hr))
1269         return hr;
1270
1271     TRACE("node_type %d\n", node_type);
1272
1273     xml_name = xmlChar_from_wchar((WCHAR*)name);
1274
1275     switch(node_type)
1276     {
1277     case NODE_ELEMENT:
1278         xmlnode = xmlNewDocNode(get_doc(This), NULL, xml_name, NULL);
1279         *node = create_node(xmlnode);
1280         TRACE("created %p\n", xmlnode);
1281         break;
1282     case NODE_ATTRIBUTE:
1283         xmlnode = (xmlNode *)xmlNewProp(NULL, xml_name, NULL);
1284         if(xmlnode)
1285         {
1286             xmlnode->doc = get_doc( This );
1287
1288             *node = (IXMLDOMNode*)create_attribute(xmlnode);
1289         }
1290
1291         TRACE("created %p\n", xmlnode);
1292         break;
1293
1294     default:
1295         FIXME("unhandled node type %d\n", node_type);
1296         break;
1297     }
1298
1299     HeapFree(GetProcessHeap(), 0, xml_name);
1300
1301     if(xmlnode && *node)
1302     {
1303         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1304         return S_OK;
1305     }
1306
1307     return E_FAIL;
1308 }
1309
1310 static HRESULT WINAPI domdoc_nodeFromID(
1311     IXMLDOMDocument2 *iface,
1312     BSTR idString,
1313     IXMLDOMNode** node )
1314 {
1315     FIXME("\n");
1316     return E_NOTIMPL;
1317 }
1318
1319 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1320 {
1321     domdoc *This = obj;
1322     xmlDocPtr xmldoc;
1323
1324     xmldoc = doparse( ptr, len );
1325     if(xmldoc) {
1326         xmldoc->_private = create_priv();
1327         attach_xmlnode(This->node, (xmlNodePtr) xmldoc);
1328     }
1329
1330     return S_OK;
1331 }
1332
1333 static HRESULT doread( domdoc *This, LPWSTR filename )
1334 {
1335     bsc_t *bsc;
1336     HRESULT hr;
1337
1338     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1339     if(FAILED(hr))
1340         return hr;
1341
1342     if(This->bsc)
1343         detach_bsc(This->bsc);
1344
1345     This->bsc = bsc;
1346     return S_OK;
1347 }
1348
1349 static HRESULT WINAPI domdoc_load(
1350     IXMLDOMDocument2 *iface,
1351     VARIANT xmlSource,
1352     VARIANT_BOOL* isSuccessful )
1353 {
1354     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1355     LPWSTR filename = NULL;
1356     HRESULT hr = S_FALSE;
1357     IXMLDOMDocument2 *pNewDoc = NULL;
1358     IStream *pStream = NULL;
1359     xmlDocPtr xmldoc;
1360
1361     TRACE("type %d\n", V_VT(&xmlSource) );
1362
1363     *isSuccessful = VARIANT_FALSE;
1364
1365     assert( This->node );
1366
1367     attach_xmlnode(This->node, NULL);
1368
1369     switch( V_VT(&xmlSource) )
1370     {
1371     case VT_BSTR:
1372         filename = V_BSTR(&xmlSource);
1373         break;
1374     case VT_UNKNOWN:
1375         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument2, (void**)&pNewDoc);
1376         if(hr == S_OK)
1377         {
1378             if(pNewDoc)
1379             {
1380                 domdoc *newDoc = impl_from_IXMLDOMDocument2( pNewDoc );
1381                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
1382                 attach_xmlnode(This->node, (xmlNodePtr) xmldoc);
1383
1384                 *isSuccessful = VARIANT_TRUE;
1385
1386                 return S_OK;
1387             }
1388         }
1389         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
1390         if(hr == S_OK)
1391         {
1392             IPersistStream *pDocStream;
1393             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
1394             if(hr == S_OK)
1395             {
1396                 hr = xmldoc_IPersistStream_Load(pDocStream, pStream);
1397                 IStream_Release(pStream);
1398                 if(hr == S_OK)
1399                 {
1400                     *isSuccessful = VARIANT_TRUE;
1401
1402                     TRACE("Using ID_IStream to load Document\n");
1403                     return S_OK;
1404                 }
1405                 else
1406                 {
1407                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
1408                 }
1409             }
1410             else
1411             {
1412                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
1413             }
1414         }
1415         else
1416         {
1417             /* ISequentialStream */
1418             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
1419         }
1420         break;
1421      default:
1422             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
1423      }
1424
1425     TRACE("filename (%s)\n", debugstr_w(filename));
1426
1427     if ( filename )
1428     {
1429         hr = doread( This, filename );
1430     
1431         if ( FAILED(hr) )
1432             This->error = E_FAIL;
1433         else
1434         {
1435             hr = This->error = S_OK;
1436             *isSuccessful = VARIANT_TRUE;
1437         }
1438     }
1439
1440     if(!filename || FAILED(hr)) {
1441         xmldoc = xmlNewDoc(NULL);
1442         xmldoc->_private = create_priv();
1443         attach_xmlnode(This->node, (xmlNodePtr) xmldoc);
1444         hr = S_FALSE;
1445     }
1446
1447     TRACE("ret (%d)\n", hr);
1448
1449     return hr;
1450 }
1451
1452
1453 static HRESULT WINAPI domdoc_get_readyState(
1454     IXMLDOMDocument2 *iface,
1455     long* value )
1456 {
1457     FIXME("\n");
1458     return E_NOTIMPL;
1459 }
1460
1461
1462 static HRESULT WINAPI domdoc_get_parseError(
1463     IXMLDOMDocument2 *iface,
1464     IXMLDOMParseError** errorObj )
1465 {
1466     BSTR error_string = NULL;
1467     static const WCHAR err[] = {'e','r','r','o','r',0};
1468     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1469
1470     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
1471
1472     if(This->error)
1473         error_string = SysAllocString(err);
1474
1475     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
1476     if(!*errorObj) return E_OUTOFMEMORY;
1477     return S_OK;
1478 }
1479
1480
1481 static HRESULT WINAPI domdoc_get_url(
1482     IXMLDOMDocument2 *iface,
1483     BSTR* urlString )
1484 {
1485     FIXME("\n");
1486     return E_NOTIMPL;
1487 }
1488
1489
1490 static HRESULT WINAPI domdoc_get_async(
1491     IXMLDOMDocument2 *iface,
1492     VARIANT_BOOL* isAsync )
1493 {
1494     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1495
1496     TRACE("%p <- %d\n", isAsync, This->async);
1497     *isAsync = This->async;
1498     return S_OK;
1499 }
1500
1501
1502 static HRESULT WINAPI domdoc_put_async(
1503     IXMLDOMDocument2 *iface,
1504     VARIANT_BOOL isAsync )
1505 {
1506     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1507
1508     TRACE("%d\n", isAsync);
1509     This->async = isAsync;
1510     return S_OK;
1511 }
1512
1513
1514 static HRESULT WINAPI domdoc_abort(
1515     IXMLDOMDocument2 *iface )
1516 {
1517     FIXME("\n");
1518     return E_NOTIMPL;
1519 }
1520
1521
1522 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
1523 {
1524     UINT len, blen = SysStringLen( bstr );
1525     LPSTR str;
1526
1527     len = WideCharToMultiByte( CP_UTF8, 0, bstr, blen, NULL, 0, NULL, NULL );
1528     str = HeapAlloc( GetProcessHeap(), 0, len );
1529     if ( !str )
1530         return FALSE;
1531     WideCharToMultiByte( CP_UTF8, 0, bstr, blen, str, len, NULL, NULL );
1532     *plen = len;
1533     *pstr = str;
1534     return TRUE;
1535 }
1536
1537 static HRESULT WINAPI domdoc_loadXML(
1538     IXMLDOMDocument2 *iface,
1539     BSTR bstrXML,
1540     VARIANT_BOOL* isSuccessful )
1541 {
1542     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1543     xmlDocPtr xmldoc = NULL;
1544     char *str;
1545     int len;
1546     HRESULT hr = S_FALSE;
1547
1548     TRACE("%p %s %p\n", This, debugstr_w( bstrXML ), isSuccessful );
1549
1550     assert ( This->node );
1551
1552     attach_xmlnode( This->node, NULL );
1553
1554     if ( isSuccessful )
1555     {
1556         *isSuccessful = VARIANT_FALSE;
1557
1558         if ( bstrXML  && bstr_to_utf8( bstrXML, &str, &len ) )
1559         {
1560             xmldoc = doparse( str, len );
1561             HeapFree( GetProcessHeap(), 0, str );
1562             if ( !xmldoc )
1563                 This->error = E_FAIL;
1564             else
1565             {
1566                 hr = This->error = S_OK;
1567                 *isSuccessful = VARIANT_TRUE;
1568             }
1569         }
1570     }
1571     if(!xmldoc)
1572         xmldoc = xmlNewDoc(NULL);
1573
1574     xmldoc->_private = create_priv();
1575     attach_xmlnode( This->node, (xmlNodePtr) xmldoc );
1576
1577     return hr;
1578 }
1579
1580
1581 static HRESULT WINAPI domdoc_save(
1582     IXMLDOMDocument2 *iface,
1583     VARIANT destination )
1584 {
1585     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1586     HANDLE handle;
1587     xmlChar *mem, *p;
1588     int size;
1589     HRESULT ret = S_OK;
1590     DWORD written;
1591
1592     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
1593           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
1594
1595     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
1596     {
1597         FIXME("Unhandled vt %d\n", V_VT(&destination));
1598         return S_FALSE;
1599     }
1600
1601     if(V_VT(&destination) == VT_UNKNOWN)
1602     {
1603         IUnknown *pUnk = V_UNKNOWN(&destination);
1604         IXMLDOMDocument *pDocument;
1605
1606         ret = IXMLDOMDocument_QueryInterface(pUnk, &IID_IXMLDOMDocument2, (void**)&pDocument);
1607         if(ret == S_OK)
1608         {
1609             BSTR bXML;
1610             VARIANT_BOOL bSuccessful;
1611
1612             ret = IXMLDOMDocument_get_xml(iface, &bXML);
1613             if(ret == S_OK)
1614             {
1615                 ret = IXMLDOMDocument_loadXML(pDocument, bXML, &bSuccessful);
1616
1617                 SysFreeString(bXML);
1618             }
1619
1620             IXMLDOMDocument_Release(pDocument);
1621         }
1622
1623         TRACE("ret %d\n", ret);
1624
1625         return ret;
1626     }
1627
1628     handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
1629                           NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1630     if( handle == INVALID_HANDLE_VALUE )
1631     {
1632         WARN("failed to create file\n");
1633         return S_FALSE;
1634     }
1635
1636     xmlDocDumpMemory(get_doc(This), &mem, &size);
1637
1638     /*
1639      * libxml2 always adds XML declaration on top of the file and one for each processing instruction node in DOM tree.
1640      * MSXML adds XML declaration only for processing instruction nodes.
1641      * We skip the first XML declaration generated by libxml2 to get exactly what we need.
1642      */
1643     p = mem;
1644     if(size > 2 && p[0] == '<' && p[1] == '?') {
1645         while(p < mem+size && (p[0] != '?' || p[1] != '>'))
1646             p++;
1647         p += 2;
1648         while(p < mem+size && isspace(*p))
1649             p++;
1650         size -= p-mem;
1651     }
1652
1653     if(!WriteFile(handle, p, (DWORD)size, &written, NULL) || written != (DWORD)size)
1654     {
1655         WARN("write error\n");
1656         ret = S_FALSE;
1657     }
1658
1659     xmlFree(mem);
1660     CloseHandle(handle);
1661     return ret;
1662 }
1663
1664 static HRESULT WINAPI domdoc_get_validateOnParse(
1665     IXMLDOMDocument2 *iface,
1666     VARIANT_BOOL* isValidating )
1667 {
1668     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1669
1670     TRACE("%p <- %d\n", isValidating, This->validating);
1671     *isValidating = This->validating;
1672     return S_OK;
1673 }
1674
1675
1676 static HRESULT WINAPI domdoc_put_validateOnParse(
1677     IXMLDOMDocument2 *iface,
1678     VARIANT_BOOL isValidating )
1679 {
1680     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1681
1682     TRACE("%d\n", isValidating);
1683     This->validating = isValidating;
1684     return S_OK;
1685 }
1686
1687
1688 static HRESULT WINAPI domdoc_get_resolveExternals(
1689     IXMLDOMDocument2 *iface,
1690     VARIANT_BOOL* isResolving )
1691 {
1692     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1693
1694     TRACE("%p <- %d\n", isResolving, This->resolving);
1695     *isResolving = This->resolving;
1696     return S_OK;
1697 }
1698
1699
1700 static HRESULT WINAPI domdoc_put_resolveExternals(
1701     IXMLDOMDocument2 *iface,
1702     VARIANT_BOOL isResolving )
1703 {
1704     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1705
1706     TRACE("%d\n", isResolving);
1707     This->resolving = isResolving;
1708     return S_OK;
1709 }
1710
1711
1712 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
1713     IXMLDOMDocument2 *iface,
1714     VARIANT_BOOL* isPreserving )
1715 {
1716     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1717
1718     TRACE("%p <- %d\n", isPreserving, This->preserving);
1719     *isPreserving = This->preserving;
1720     return S_OK;
1721 }
1722
1723
1724 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
1725     IXMLDOMDocument2 *iface,
1726     VARIANT_BOOL isPreserving )
1727 {
1728     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1729
1730     TRACE("%d\n", isPreserving);
1731     This->preserving = isPreserving;
1732     return S_OK;
1733 }
1734
1735
1736 static HRESULT WINAPI domdoc_put_onReadyStateChange(
1737     IXMLDOMDocument2 *iface,
1738     VARIANT readyStateChangeSink )
1739 {
1740     FIXME("\n");
1741     return E_NOTIMPL;
1742 }
1743
1744
1745 static HRESULT WINAPI domdoc_put_onDataAvailable(
1746     IXMLDOMDocument2 *iface,
1747     VARIANT onDataAvailableSink )
1748 {
1749     FIXME("\n");
1750     return E_NOTIMPL;
1751 }
1752
1753 static HRESULT WINAPI domdoc_put_onTransformNode(
1754     IXMLDOMDocument2 *iface,
1755     VARIANT onTransformNodeSink )
1756 {
1757     FIXME("\n");
1758     return E_NOTIMPL;
1759 }
1760
1761 static HRESULT WINAPI domdoc_get_namespaces(
1762     IXMLDOMDocument2* iface,
1763     IXMLDOMSchemaCollection** schemaCollection )
1764 {
1765     FIXME("\n");
1766     return E_NOTIMPL;
1767 }
1768
1769 static HRESULT WINAPI domdoc_get_schemas(
1770     IXMLDOMDocument2* iface,
1771     VARIANT* var1 )
1772 {
1773     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1774     HRESULT hr = S_FALSE;
1775     IXMLDOMSchemaCollection *cur_schema = This->schema;
1776
1777     TRACE("(%p)->(%p)\n", This, var1);
1778
1779     VariantInit(var1); /* Test shows we don't call VariantClear here */
1780     V_VT(var1) = VT_NULL;
1781
1782     if(cur_schema)
1783     {
1784         hr = IXMLDOMSchemaCollection_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
1785         if(SUCCEEDED(hr))
1786             V_VT(var1) = VT_DISPATCH;
1787     }
1788     return hr;
1789 }
1790
1791 static HRESULT WINAPI domdoc_putref_schemas(
1792     IXMLDOMDocument2* iface,
1793     VARIANT var1)
1794 {
1795     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1796     HRESULT hr = E_FAIL;
1797     IXMLDOMSchemaCollection *new_schema = NULL;
1798
1799     FIXME("(%p): semi-stub\n", This);
1800     switch(V_VT(&var1))
1801     {
1802     case VT_UNKNOWN:
1803         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
1804         break;
1805
1806     case VT_DISPATCH:
1807         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
1808         break;
1809
1810     case VT_NULL:
1811     case VT_EMPTY:
1812         hr = S_OK;
1813         break;
1814
1815     default:
1816         WARN("Can't get schema from vt %x\n", V_VT(&var1));
1817     }
1818
1819     if(SUCCEEDED(hr))
1820     {
1821         IXMLDOMSchemaCollection *old_schema = InterlockedExchangePointer((void**)&This->schema, new_schema);
1822         if(old_schema) IXMLDOMSchemaCollection_Release(old_schema);
1823     }
1824
1825     return hr;
1826 }
1827
1828 static HRESULT WINAPI domdoc_validate(
1829     IXMLDOMDocument2* iface,
1830     IXMLDOMParseError** err)
1831 {
1832     FIXME("\n");
1833     return E_NOTIMPL;
1834 }
1835
1836 static HRESULT WINAPI domdoc_setProperty(
1837     IXMLDOMDocument2* iface,
1838     BSTR p,
1839     VARIANT var)
1840 {
1841     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1842
1843     if (lstrcmpiW(p, SZ_PROPERTY_SELECTION_LANGUAGE) == 0)
1844     {
1845         VARIANT varStr;
1846         HRESULT hr;
1847         BSTR bstr;
1848
1849         V_VT(&varStr) = VT_EMPTY;
1850         if (V_VT(&var) != VT_BSTR)
1851         {
1852             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
1853                 return hr;
1854             bstr = V_BSTR(&varStr);
1855         }
1856         else
1857             bstr = V_BSTR(&var);
1858
1859         hr = S_OK;
1860         if (lstrcmpiW(bstr, SZ_VALUE_XPATH) == 0)
1861             This->bUseXPath = TRUE;
1862         else if (lstrcmpiW(bstr, SZ_VALUE_XSLPATTERN) == 0)
1863             This->bUseXPath = FALSE;
1864         else
1865             hr = E_FAIL;
1866
1867         VariantClear(&varStr);
1868         return hr;
1869     }
1870
1871     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
1872     return E_FAIL;
1873 }
1874
1875 static HRESULT WINAPI domdoc_getProperty(
1876     IXMLDOMDocument2* iface,
1877     BSTR p,
1878     VARIANT* var)
1879 {
1880     domdoc *This = impl_from_IXMLDOMDocument2( iface );
1881
1882     if (var == NULL)
1883         return E_INVALIDARG;
1884     if (lstrcmpiW(p, SZ_PROPERTY_SELECTION_LANGUAGE) == 0)
1885     {
1886         V_VT(var) = VT_BSTR;
1887         if (This->bUseXPath)
1888             V_BSTR(var) = SysAllocString(SZ_VALUE_XPATH);
1889         else
1890             V_BSTR(var) = SysAllocString(SZ_VALUE_XSLPATTERN);
1891         return S_OK;
1892     }
1893
1894     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
1895     return E_FAIL;
1896 }
1897
1898 static const struct IXMLDOMDocument2Vtbl domdoc_vtbl =
1899 {
1900     domdoc_QueryInterface,
1901     domdoc_AddRef,
1902     domdoc_Release,
1903     domdoc_GetTypeInfoCount,
1904     domdoc_GetTypeInfo,
1905     domdoc_GetIDsOfNames,
1906     domdoc_Invoke,
1907     domdoc_get_nodeName,
1908     domdoc_get_nodeValue,
1909     domdoc_put_nodeValue,
1910     domdoc_get_nodeType,
1911     domdoc_get_parentNode,
1912     domdoc_get_childNodes,
1913     domdoc_get_firstChild,
1914     domdoc_get_lastChild,
1915     domdoc_get_previousSibling,
1916     domdoc_get_nextSibling,
1917     domdoc_get_attributes,
1918     domdoc_insertBefore,
1919     domdoc_replaceChild,
1920     domdoc_removeChild,
1921     domdoc_appendChild,
1922     domdoc_hasChildNodes,
1923     domdoc_get_ownerDocument,
1924     domdoc_cloneNode,
1925     domdoc_get_nodeTypeString,
1926     domdoc_get_text,
1927     domdoc_put_text,
1928     domdoc_get_specified,
1929     domdoc_get_definition,
1930     domdoc_get_nodeTypedValue,
1931     domdoc_put_nodeTypedValue,
1932     domdoc_get_dataType,
1933     domdoc_put_dataType,
1934     domdoc_get_xml,
1935     domdoc_transformNode,
1936     domdoc_selectNodes,
1937     domdoc_selectSingleNode,
1938     domdoc_get_parsed,
1939     domdoc_get_namespaceURI,
1940     domdoc_get_prefix,
1941     domdoc_get_baseName,
1942     domdoc_transformNodeToObject,
1943     domdoc_get_doctype,
1944     domdoc_get_implementation,
1945     domdoc_get_documentElement,
1946     domdoc_put_documentElement,
1947     domdoc_createElement,
1948     domdoc_createDocumentFragment,
1949     domdoc_createTextNode,
1950     domdoc_createComment,
1951     domdoc_createCDATASection,
1952     domdoc_createProcessingInstruction,
1953     domdoc_createAttribute,
1954     domdoc_createEntityReference,
1955     domdoc_getElementsByTagName,
1956     domdoc_createNode,
1957     domdoc_nodeFromID,
1958     domdoc_load,
1959     domdoc_get_readyState,
1960     domdoc_get_parseError,
1961     domdoc_get_url,
1962     domdoc_get_async,
1963     domdoc_put_async,
1964     domdoc_abort,
1965     domdoc_loadXML,
1966     domdoc_save,
1967     domdoc_get_validateOnParse,
1968     domdoc_put_validateOnParse,
1969     domdoc_get_resolveExternals,
1970     domdoc_put_resolveExternals,
1971     domdoc_get_preserveWhiteSpace,
1972     domdoc_put_preserveWhiteSpace,
1973     domdoc_put_onReadyStateChange,
1974     domdoc_put_onDataAvailable,
1975     domdoc_put_onTransformNode,
1976     domdoc_get_namespaces,
1977     domdoc_get_schemas,
1978     domdoc_putref_schemas,
1979     domdoc_validate,
1980     domdoc_setProperty,
1981     domdoc_getProperty
1982 };
1983
1984 /* xmldoc implementation of IObjectWithSite */
1985 static HRESULT WINAPI
1986 xmldoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
1987 {
1988     domdoc *This = impl_from_IObjectWithSite(iface);
1989     return IXMLDocument_QueryInterface( (IXMLDocument *)This, riid, ppvObject );
1990 }
1991
1992 static ULONG WINAPI
1993 xmldoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
1994 {
1995     domdoc *This = impl_from_IObjectWithSite(iface);
1996     return IXMLDocument_AddRef((IXMLDocument *)This);
1997 }
1998
1999 static ULONG WINAPI
2000 xmldoc_ObjectWithSite_Release( IObjectWithSite* iface )
2001 {
2002     domdoc *This = impl_from_IObjectWithSite(iface);
2003     return IXMLDocument_Release((IXMLDocument *)This);
2004 }
2005
2006 static HRESULT WINAPI
2007 xmldoc_GetSite( IObjectWithSite *iface, REFIID iid, void ** ppvSite )
2008 {
2009     domdoc *This = impl_from_IObjectWithSite(iface);
2010
2011     TRACE("%p %s %p\n", This, debugstr_guid( iid ), ppvSite );
2012
2013     if ( !This->site )
2014         return E_FAIL;
2015
2016     return IUnknown_QueryInterface( This->site, iid, ppvSite );
2017 }
2018
2019 static HRESULT WINAPI
2020 xmldoc_SetSite( IObjectWithSite *iface, IUnknown *punk )
2021 {
2022     domdoc *This = impl_from_IObjectWithSite(iface);
2023
2024     TRACE("%p %p\n", iface, punk);
2025
2026     if(!punk)
2027     {
2028         if(This->site)
2029         {
2030             IUnknown_Release( This->site );
2031             This->site = NULL;
2032         }
2033
2034         return S_OK;
2035     }
2036
2037     if ( punk )
2038         IUnknown_AddRef( punk );
2039
2040     if(This->site)
2041         IUnknown_Release( This->site );
2042
2043     This->site = punk;
2044
2045     return S_OK;
2046 }
2047
2048 static const IObjectWithSiteVtbl domdocObjectSite =
2049 {
2050     xmldoc_ObjectWithSite_QueryInterface,
2051     xmldoc_ObjectWithSite_AddRef,
2052     xmldoc_ObjectWithSite_Release,
2053     xmldoc_SetSite,
2054     xmldoc_GetSite,
2055 };
2056
2057 static HRESULT WINAPI xmldoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
2058 {
2059     domdoc *This = impl_from_IObjectSafety(iface);
2060     return IXMLDocument_QueryInterface( (IXMLDocument *)This, riid, ppv );
2061 }
2062
2063 static ULONG WINAPI xmldoc_Safety_AddRef(IObjectSafety *iface)
2064 {
2065     domdoc *This = impl_from_IObjectSafety(iface);
2066     return IXMLDocument_AddRef((IXMLDocument *)This);
2067 }
2068
2069 static ULONG WINAPI xmldoc_Safety_Release(IObjectSafety *iface)
2070 {
2071     domdoc *This = impl_from_IObjectSafety(iface);
2072     return IXMLDocument_Release((IXMLDocument *)This);
2073 }
2074
2075 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
2076
2077 static HRESULT WINAPI xmldoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
2078         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
2079 {
2080     domdoc *This = impl_from_IObjectSafety(iface);
2081
2082     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
2083
2084     if(!pdwSupportedOptions || !pdwEnabledOptions)
2085         return E_POINTER;
2086
2087     *pdwSupportedOptions = SUPPORTED_OPTIONS;
2088     *pdwEnabledOptions = This->safeopt;
2089
2090     return S_OK;
2091 }
2092
2093 static HRESULT WINAPI xmldoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
2094         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
2095 {
2096     domdoc *This = impl_from_IObjectSafety(iface);
2097
2098     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
2099
2100     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
2101         return E_FAIL;
2102
2103     This->safeopt = dwEnabledOptions & dwEnabledOptions;
2104     return S_OK;
2105 }
2106
2107 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
2108     xmldoc_Safety_QueryInterface,
2109     xmldoc_Safety_AddRef,
2110     xmldoc_Safety_Release,
2111     xmldoc_Safety_GetInterfaceSafetyOptions,
2112     xmldoc_Safety_SetInterfaceSafetyOptions
2113 };
2114
2115
2116 static const tid_t domdoc_iface_tids[] = {
2117     IXMLDOMNode_tid,
2118     IXMLDOMDocument_tid,
2119     IXMLDOMDocument2_tid,
2120     0
2121 };
2122 static dispex_static_data_t domdoc_dispex = {
2123     NULL,
2124     IXMLDOMDocument2_tid,
2125     NULL,
2126     domdoc_iface_tids
2127 };
2128
2129 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument2 **document)
2130 {
2131     domdoc *doc;
2132     HRESULT hr;
2133
2134     doc = HeapAlloc( GetProcessHeap(), 0, sizeof (*doc) );
2135     if( !doc )
2136         return E_OUTOFMEMORY;
2137
2138     doc->lpVtbl = &domdoc_vtbl;
2139     doc->lpvtblIPersistStream = &xmldoc_IPersistStream_VTable;
2140     doc->lpvtblIObjectWithSite = &domdocObjectSite;
2141     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
2142     doc->ref = 1;
2143     doc->async = 0;
2144     doc->validating = 0;
2145     doc->resolving = 0;
2146     doc->preserving = 0;
2147     doc->bUseXPath = FALSE;
2148     doc->error = S_OK;
2149     doc->schema = NULL;
2150     doc->stream = NULL;
2151     doc->site = NULL;
2152     doc->safeopt = 0;
2153     doc->bsc = NULL;
2154
2155     doc->node_unk = create_basic_node( (xmlNodePtr)xmldoc, (IUnknown*)&doc->lpVtbl );
2156     if(!doc->node_unk)
2157     {
2158         HeapFree(GetProcessHeap(), 0, doc);
2159         return E_FAIL;
2160     }
2161
2162     hr = IUnknown_QueryInterface(doc->node_unk, &IID_IXMLDOMNode, (LPVOID*)&doc->node);
2163     if(FAILED(hr))
2164     {
2165         IUnknown_Release(doc->node_unk);
2166         HeapFree( GetProcessHeap(), 0, doc );
2167         return E_FAIL;
2168     }
2169
2170     init_dispex(&doc->dispex, (IUnknown*)&doc->lpVtbl, &domdoc_dispex);
2171
2172     /* The ref on doc->node is actually looped back into this object, so release it */
2173     IXMLDOMNode_Release(doc->node);
2174
2175     *document = (IXMLDOMDocument2*)&doc->lpVtbl;
2176
2177     TRACE("returning iface %p\n", *document);
2178     return S_OK;
2179 }
2180
2181 HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
2182 {
2183     xmlDocPtr xmldoc;
2184     HRESULT hr;
2185
2186     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
2187
2188     xmldoc = xmlNewDoc(NULL);
2189     if(!xmldoc)
2190         return E_OUTOFMEMORY;
2191
2192     xmldoc->_private = create_priv();
2193
2194     hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument2**)ppObj);
2195     if(FAILED(hr))
2196         xmlFreeDoc(xmldoc);
2197
2198     return hr;
2199 }
2200
2201 IUnknown* create_domdoc( xmlNodePtr document )
2202 {
2203     HRESULT hr;
2204     LPVOID pObj = NULL;
2205
2206     TRACE("(%p)\n", document);
2207
2208     hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument2**)&pObj);
2209     if (FAILED(hr))
2210         return NULL;
2211
2212     return (IUnknown*)pObj;
2213 }
2214
2215 #else
2216
2217 HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
2218 {
2219     MESSAGE("This program tried to use a DOMDocument object, but\n"
2220             "libxml2 support was not present at compile time.\n");
2221     return E_NOTIMPL;
2222 }
2223
2224 #endif