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