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