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