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