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