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