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