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