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