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