msxml3: Forward IDispatch to IDispatchEx when supported.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2010-2011 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 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
37
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
50
51 #include "wine/debug.h"
52 #include "wine/list.h"
53
54 #include "msxml_private.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
57
58 #ifdef HAVE_LIBXML2
59
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT     1
62 #define XML_SAVE_NO_DECL    2
63 #define XML_SAVE_NO_EMPTY   4
64 #define XML_SAVE_NO_XHTML   8
65 #define XML_SAVE_XHTML     16
66 #define XML_SAVE_AS_XML    32
67 #define XML_SAVE_AS_HTML   64
68
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
76
77 /* Anything that passes the test_get_ownerDocument()
78  * tests can go here (data shared between all instances).
79  * We need to preserve this when reloading a document,
80  * and also need access to it from the libxml backend. */
81 typedef struct _domdoc_properties {
82     MSXML_VERSION version;
83     VARIANT_BOOL preserving;
84     IXMLDOMSchemaCollection2* schemaCache;
85     struct list selectNsList;
86     xmlChar const* selectNsStr;
87     LONG selectNsStr_len;
88     BOOL XPath;
89 } domdoc_properties;
90
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
93
94 struct ConnectionPoint
95 {
96     IConnectionPoint IConnectionPoint_iface;
97     const IID *iid;
98
99     ConnectionPoint *next;
100     IConnectionPointContainer *container;
101     domdoc *doc;
102
103     union
104     {
105         IUnknown *unk;
106         IDispatch *disp;
107         IPropertyNotifySink *propnotif;
108     } *sinks;
109     DWORD sinks_size;
110 };
111
112 typedef enum {
113     EVENTID_READYSTATECHANGE = 0,
114     EVENTID_DATAAVAILABLE,
115     EVENTID_TRANSFORMNODE,
116     EVENTID_LAST
117 } eventid_t;
118
119 struct domdoc
120 {
121     xmlnode node;
122     IXMLDOMDocument3          IXMLDOMDocument3_iface;
123     IPersistStreamInit        IPersistStreamInit_iface;
124     IObjectWithSite           IObjectWithSite_iface;
125     IObjectSafety             IObjectSafety_iface;
126     IConnectionPointContainer IConnectionPointContainer_iface;
127     LONG ref;
128     VARIANT_BOOL async;
129     VARIANT_BOOL validating;
130     VARIANT_BOOL resolving;
131     domdoc_properties* properties;
132     bsc_t *bsc;
133     HRESULT error;
134
135     /* IPersistStream */
136     IStream *stream;
137
138     /* IObjectWithSite*/
139     IUnknown *site;
140
141     /* IObjectSafety */
142     DWORD safeopt;
143
144     /* connection list */
145     ConnectionPoint *cp_list;
146     ConnectionPoint cp_domdocevents;
147     ConnectionPoint cp_propnotif;
148     ConnectionPoint cp_dispatch;
149
150     /* events */
151     IDispatch *events[EVENTID_LAST];
152 };
153
154 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 {
156     IDispatch *disp;
157
158     switch (V_VT(v))
159     {
160     case VT_UNKNOWN:
161         if (V_UNKNOWN(v))
162             IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
163         else
164             disp = NULL;
165         break;
166     case VT_DISPATCH:
167         disp = V_DISPATCH(v);
168         if (disp) IDispatch_AddRef(disp);
169         break;
170     default:
171         return DISP_E_TYPEMISMATCH;
172     }
173
174     if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
175     doc->events[eid] = disp;
176
177     return S_OK;
178 }
179
180 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 {
182     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
183 }
184
185 /*
186   In native windows, the whole lifetime management of XMLDOMNodes is
187   managed automatically using reference counts. Wine emulates that by
188   maintaining a reference count to the document that is increased for
189   each IXMLDOMNode pointer passed out for this document. If all these
190   pointers are gone, the document is unreachable and gets freed, that
191   is, all nodes in the tree of the document get freed.
192
193   You are able to create nodes that are associated to a document (in
194   fact, in msxml's XMLDOM model, all nodes are associated to a document),
195   but not in the tree of that document, for example using the createFoo
196   functions from IXMLDOMDocument. These nodes do not get cleaned up
197   by libxml, so we have to do it ourselves.
198
199   To catch these nodes, a list of "orphan nodes" is introduced.
200   It contains pointers to all roots of node trees that are
201   associated with the document without being part of the document
202   tree. All nodes with parent==NULL (except for the document root nodes)
203   should be in the orphan node list of their document. All orphan nodes
204   get freed together with the document itself.
205  */
206
207 typedef struct _xmldoc_priv {
208     LONG refs;
209     struct list orphans;
210     domdoc_properties* properties;
211 } xmldoc_priv;
212
213 typedef struct _orphan_entry {
214     struct list entry;
215     xmlNode * node;
216 } orphan_entry;
217
218 typedef struct _select_ns_entry {
219     struct list entry;
220     xmlChar const* prefix;
221     xmlChar prefix_end;
222     xmlChar const* href;
223     xmlChar href_end;
224 } select_ns_entry;
225
226 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 {
228     return doc->_private;
229 }
230
231 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 {
233     return priv_from_xmlDocPtr(doc)->properties;
234 }
235
236 BOOL is_xpathmode(const xmlDocPtr doc)
237 {
238     return properties_from_xmlDocPtr(doc)->XPath;
239 }
240
241 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 {
243     properties_from_xmlDocPtr(doc)->XPath = xpath;
244 }
245
246 int registerNamespaces(xmlXPathContextPtr ctxt)
247 {
248     int n = 0;
249     const select_ns_entry* ns = NULL;
250     const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251
252     TRACE("(%p)\n", ctxt);
253
254     LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255     {
256         xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
257         ++n;
258     }
259
260     return n;
261 }
262
263 static inline void clear_selectNsList(struct list* pNsList)
264 {
265     select_ns_entry *ns, *ns2;
266     LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267     {
268         heap_free( ns );
269     }
270     list_init(pNsList);
271 }
272
273 static xmldoc_priv * create_priv(void)
274 {
275     xmldoc_priv *priv;
276     priv = heap_alloc( sizeof (*priv) );
277
278     if (priv)
279     {
280         priv->refs = 0;
281         list_init( &priv->orphans );
282         priv->properties = NULL;
283     }
284
285     return priv;
286 }
287
288 static domdoc_properties * create_properties(MSXML_VERSION version)
289 {
290     domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291
292     list_init(&properties->selectNsList);
293     properties->preserving = VARIANT_FALSE;
294     properties->schemaCache = NULL;
295     properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
296     properties->selectNsStr_len = 0;
297
298     /* properties that are dependent on object versions */
299     properties->version = version;
300     properties->XPath = (version == MSXML4 || version == MSXML6);
301
302     return properties;
303 }
304
305 static domdoc_properties* copy_properties(domdoc_properties const* properties)
306 {
307     domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
308     select_ns_entry const* ns = NULL;
309     select_ns_entry* new_ns = NULL;
310     int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
311     ptrdiff_t offset;
312
313     if (pcopy)
314     {
315         pcopy->version = properties->version;
316         pcopy->preserving = properties->preserving;
317         pcopy->schemaCache = properties->schemaCache;
318         if (pcopy->schemaCache)
319             IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
320         pcopy->XPath = properties->XPath;
321         pcopy->selectNsStr_len = properties->selectNsStr_len;
322         list_init( &pcopy->selectNsList );
323         pcopy->selectNsStr = heap_alloc(len);
324         memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
325         offset = pcopy->selectNsStr - properties->selectNsStr;
326
327         LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
328         {
329             new_ns = heap_alloc(sizeof(select_ns_entry));
330             memcpy(new_ns, ns, sizeof(select_ns_entry));
331             new_ns->href += offset;
332             new_ns->prefix += offset;
333             list_add_tail(&pcopy->selectNsList, &new_ns->entry);
334         }
335
336     }
337
338     return pcopy;
339 }
340
341 static void free_properties(domdoc_properties* properties)
342 {
343     if (properties)
344     {
345         if (properties->schemaCache)
346             IXMLDOMSchemaCollection2_Release(properties->schemaCache);
347         clear_selectNsList(&properties->selectNsList);
348         heap_free((xmlChar*)properties->selectNsStr);
349         heap_free(properties);
350     }
351 }
352
353 /* links a "<?xml" node as a first child */
354 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
355 {
356     assert(doc != NULL);
357     if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
358 }
359
360 /* unlinks a first "<?xml" child if it was created */
361 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
362 {
363     xmlNodePtr node;
364
365     assert(doc != NULL);
366
367     if (doc->standalone != -1)
368     {
369         node = doc->children;
370         xmlUnlinkNode( node );
371     }
372     else
373         node = NULL;
374
375     return node;
376 }
377
378 BOOL is_preserving_whitespace(xmlNodePtr node)
379 {
380     domdoc_properties* properties = NULL;
381     /* during parsing the xmlDoc._private stuff is not there */
382     if (priv_from_xmlDocPtr(node->doc))
383         properties = properties_from_xmlDocPtr(node->doc);
384     return ((properties && properties->preserving == VARIANT_TRUE) ||
385             xmlNodeGetSpacePreserve(node) == 1);
386 }
387
388 static inline BOOL strn_isspace(xmlChar const* str, int len)
389 {
390     for (; str && len > 0 && *str; ++str, --len)
391         if (!isspace(*str))
392             break;
393
394     return len == 0;
395 }
396
397 static void sax_characters(void *ctx, const xmlChar *ch, int len)
398 {
399     xmlParserCtxtPtr ctxt;
400     const domdoc *This;
401
402     ctxt = (xmlParserCtxtPtr) ctx;
403     This = (const domdoc*) ctxt->_private;
404
405     if (ctxt->node)
406     {
407         /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
408         if (!This->properties->preserving &&
409             !is_preserving_whitespace(ctxt->node) &&
410             strn_isspace(ch, len))
411             return;
412     }
413
414     xmlSAX2Characters(ctxt, ch, len);
415 }
416
417 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
418 {
419     va_list ap;
420     va_start(ap, msg);
421     LIBXML2_CALLBACK_ERR(doparse, msg, ap);
422     va_end(ap);
423 }
424
425 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
426 {
427     va_list ap;
428     va_start(ap, msg);
429     LIBXML2_CALLBACK_WARN(doparse, msg, ap);
430     va_end(ap);
431 }
432
433 static void sax_serror(void* ctx, xmlErrorPtr err)
434 {
435     LIBXML2_CALLBACK_SERROR(doparse, err);
436 }
437
438 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
439 {
440     xmlDocPtr doc = NULL;
441     xmlParserCtxtPtr pctx;
442     static xmlSAXHandler sax_handler = {
443         xmlSAX2InternalSubset,          /* internalSubset */
444         xmlSAX2IsStandalone,            /* isStandalone */
445         xmlSAX2HasInternalSubset,       /* hasInternalSubset */
446         xmlSAX2HasExternalSubset,       /* hasExternalSubset */
447         xmlSAX2ResolveEntity,           /* resolveEntity */
448         xmlSAX2GetEntity,               /* getEntity */
449         xmlSAX2EntityDecl,              /* entityDecl */
450         xmlSAX2NotationDecl,            /* notationDecl */
451         xmlSAX2AttributeDecl,           /* attributeDecl */
452         xmlSAX2ElementDecl,             /* elementDecl */
453         xmlSAX2UnparsedEntityDecl,      /* unparsedEntityDecl */
454         xmlSAX2SetDocumentLocator,      /* setDocumentLocator */
455         xmlSAX2StartDocument,           /* startDocument */
456         xmlSAX2EndDocument,             /* endDocument */
457         xmlSAX2StartElement,            /* startElement */
458         xmlSAX2EndElement,              /* endElement */
459         xmlSAX2Reference,               /* reference */
460         sax_characters,                 /* characters */
461         sax_characters,                 /* ignorableWhitespace */
462         xmlSAX2ProcessingInstruction,   /* processingInstruction */
463         xmlSAX2Comment,                 /* comment */
464         sax_warning,                    /* warning */
465         sax_error,                      /* error */
466         sax_error,                      /* fatalError */
467         xmlSAX2GetParameterEntity,      /* getParameterEntity */
468         xmlSAX2CDataBlock,              /* cdataBlock */
469         xmlSAX2ExternalSubset,          /* externalSubset */
470         0,                              /* initialized */
471         NULL,                           /* _private */
472         xmlSAX2StartElementNs,          /* startElementNs */
473         xmlSAX2EndElementNs,            /* endElementNs */
474         sax_serror                      /* serror */
475     };
476     xmlInitParser();
477
478     pctx = xmlCreateMemoryParserCtxt(ptr, len);
479     if (!pctx)
480     {
481         ERR("Failed to create parser context\n");
482         return NULL;
483     }
484
485     if (pctx->sax) xmlFree(pctx->sax);
486     pctx->sax = &sax_handler;
487     pctx->_private = This;
488     pctx->recovery = 0;
489
490     if (encoding != XML_CHAR_ENCODING_NONE)
491         xmlSwitchEncoding(pctx, encoding);
492
493     xmlParseDocument(pctx);
494
495     if (pctx->wellFormed)
496     {
497         doc = pctx->myDoc;
498     }
499     else
500     {
501        xmlFreeDoc(pctx->myDoc);
502        pctx->myDoc = NULL;
503     }
504     pctx->sax = NULL;
505     xmlFreeParserCtxt(pctx);
506
507     /* TODO: put this in one of the SAX callbacks */
508     /* create first child as a <?xml...?> */
509     if (doc && doc->standalone != -1)
510     {
511         xmlNodePtr node;
512         char buff[30];
513         xmlChar *xmlbuff = (xmlChar*)buff;
514
515         node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
516
517         /* version attribute can't be omitted */
518         sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
519         xmlNodeAddContent( node, xmlbuff );
520
521         if (doc->encoding)
522         {
523             sprintf(buff, " encoding=\"%s\"", doc->encoding);
524             xmlNodeAddContent( node, xmlbuff );
525         }
526
527         if (doc->standalone != -2)
528         {
529             sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
530             xmlNodeAddContent( node, xmlbuff );
531         }
532
533         xmldoc_link_xmldecl( doc, node );
534     }
535
536     return doc;
537 }
538
539 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
540 {
541     doc->_private = create_priv();
542     priv_from_xmlDocPtr(doc)->properties = create_properties(version);
543 }
544
545 LONG xmldoc_add_ref(xmlDocPtr doc)
546 {
547     LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
548     TRACE("(%p)->(%d)\n", doc, ref);
549     return ref;
550 }
551
552 LONG xmldoc_release(xmlDocPtr doc)
553 {
554     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
555     LONG ref = InterlockedDecrement(&priv->refs);
556     TRACE("(%p)->(%d)\n", doc, ref);
557     if(ref == 0)
558     {
559         orphan_entry *orphan, *orphan2;
560         TRACE("freeing docptr %p\n", doc);
561
562         LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
563         {
564             xmlFreeNode( orphan->node );
565             heap_free( orphan );
566         }
567         free_properties(priv->properties);
568         heap_free(doc->_private);
569
570         xmlFreeDoc(doc);
571     }
572
573     return ref;
574 }
575
576 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
577 {
578     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
579     orphan_entry *entry;
580
581     entry = heap_alloc( sizeof (*entry) );
582     if(!entry)
583         return E_OUTOFMEMORY;
584
585     entry->node = node;
586     list_add_head( &priv->orphans, &entry->entry );
587     return S_OK;
588 }
589
590 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
591 {
592     xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
593     orphan_entry *entry, *entry2;
594
595     LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
596     {
597         if( entry->node == node )
598         {
599             list_remove( &entry->entry );
600             heap_free( entry );
601             return S_OK;
602         }
603     }
604
605     return S_FALSE;
606 }
607
608 static inline xmlDocPtr get_doc( domdoc *This )
609 {
610     return (xmlDocPtr)This->node.node;
611 }
612
613 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
614 {
615     if(This->node.node)
616     {
617         priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
618         if (xmldoc_release(get_doc(This)) != 0)
619             priv_from_xmlDocPtr(get_doc(This))->properties =
620                 copy_properties(This->properties);
621     }
622
623     This->node.node = (xmlNodePtr) xml;
624
625     if(This->node.node)
626     {
627         xmldoc_add_ref(get_doc(This));
628         priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
629     }
630
631     return S_OK;
632 }
633
634 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
635 {
636     return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
637 }
638
639 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
640 {
641     return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
642 }
643
644 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
645 {
646     return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
647 }
648
649 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
650 {
651     return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
652 }
653
654 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
655 {
656     return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
657 }
658
659 /************************************************************************
660  * domdoc implementation of IPersistStream.
661  */
662 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
663     IPersistStreamInit *iface, REFIID riid, void **ppvObj)
664 {
665     domdoc* This = impl_from_IPersistStreamInit(iface);
666     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
667 }
668
669 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
670     IPersistStreamInit *iface)
671 {
672     domdoc* This = impl_from_IPersistStreamInit(iface);
673     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
674 }
675
676 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
677     IPersistStreamInit *iface)
678 {
679     domdoc* This = impl_from_IPersistStreamInit(iface);
680     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
681 }
682
683 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
684     IPersistStreamInit *iface, CLSID *classid)
685 {
686     domdoc* This = impl_from_IPersistStreamInit(iface);
687     TRACE("(%p)->(%p)\n", This, classid);
688
689     if(!classid)
690         return E_POINTER;
691
692     *classid = *DOMDocument_version(This->properties->version);
693
694     return S_OK;
695 }
696
697 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
698     IPersistStreamInit *iface)
699 {
700     domdoc *This = impl_from_IPersistStreamInit(iface);
701     FIXME("(%p): stub!\n", This);
702     return S_FALSE;
703 }
704
705 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
706     IPersistStreamInit *iface, LPSTREAM pStm)
707 {
708     domdoc *This = impl_from_IPersistStreamInit(iface);
709     HRESULT hr;
710     HGLOBAL hglobal;
711     DWORD read, written, len;
712     BYTE buf[4096];
713     char *ptr;
714     xmlDocPtr xmldoc = NULL;
715
716     TRACE("(%p)->(%p)\n", This, pStm);
717
718     if (!pStm)
719         return E_INVALIDARG;
720
721     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
722     if (FAILED(hr))
723         return hr;
724
725     do
726     {
727         IStream_Read(pStm, buf, sizeof(buf), &read);
728         hr = IStream_Write(This->stream, buf, read, &written);
729     } while(SUCCEEDED(hr) && written != 0 && read != 0);
730
731     if (FAILED(hr))
732     {
733         ERR("Failed to copy stream\n");
734         return hr;
735     }
736
737     hr = GetHGlobalFromStream(This->stream, &hglobal);
738     if (FAILED(hr))
739         return hr;
740
741     len = GlobalSize(hglobal);
742     ptr = GlobalLock(hglobal);
743     if (len != 0)
744         xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
745     GlobalUnlock(hglobal);
746
747     if (!xmldoc)
748     {
749         ERR("Failed to parse xml\n");
750         return E_FAIL;
751     }
752
753     xmldoc->_private = create_priv();
754
755     return attach_xmldoc(This, xmldoc);
756 }
757
758 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
759     IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
760 {
761     domdoc *This = impl_from_IPersistStreamInit(iface);
762     BSTR xmlString;
763     HRESULT hr;
764
765     TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
766
767     hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
768     if(hr == S_OK)
769     {
770         DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
771
772         hr = IStream_Write( stream, xmlString, len, NULL );
773         SysFreeString(xmlString);
774     }
775
776     TRACE("ret 0x%08x\n", hr);
777
778     return hr;
779 }
780
781 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
782     IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
783 {
784     domdoc *This = impl_from_IPersistStreamInit(iface);
785     TRACE("(%p)->(%p): stub!\n", This, pcbSize);
786     return E_NOTIMPL;
787 }
788
789 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
790     IPersistStreamInit *iface)
791 {
792     domdoc *This = impl_from_IPersistStreamInit(iface);
793     TRACE("(%p)\n", This);
794     return S_OK;
795 }
796
797 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
798 {
799     domdoc_IPersistStreamInit_QueryInterface,
800     domdoc_IPersistStreamInit_AddRef,
801     domdoc_IPersistStreamInit_Release,
802     domdoc_IPersistStreamInit_GetClassID,
803     domdoc_IPersistStreamInit_IsDirty,
804     domdoc_IPersistStreamInit_Load,
805     domdoc_IPersistStreamInit_Save,
806     domdoc_IPersistStreamInit_GetSizeMax,
807     domdoc_IPersistStreamInit_InitNew
808 };
809
810 /* IXMLDOMDocument3 interface */
811
812 static const tid_t domdoc_se_tids[] = {
813     IXMLDOMNode_tid,
814     IXMLDOMDocument_tid,
815     IXMLDOMDocument2_tid,
816     IXMLDOMDocument3_tid,
817     0
818 };
819
820 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
821 {
822     domdoc *This = impl_from_IXMLDOMDocument3( iface );
823
824     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
825
826     *ppvObject = NULL;
827
828     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
829          IsEqualGUID( riid, &IID_IDispatch ) ||
830          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
831          IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
832          IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
833          IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
834     {
835         *ppvObject = iface;
836     }
837     else if (IsEqualGUID(&IID_IPersistStream, riid) ||
838              IsEqualGUID(&IID_IPersistStreamInit, riid))
839     {
840         *ppvObject = &This->IPersistStreamInit_iface;
841     }
842     else if (IsEqualGUID(&IID_IObjectWithSite, riid))
843     {
844         *ppvObject = &This->IObjectWithSite_iface;
845     }
846     else if (IsEqualGUID(&IID_IObjectSafety, riid))
847     {
848         *ppvObject = &This->IObjectSafety_iface;
849     }
850     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
851     {
852         return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
853     }
854     else if(node_query_interface(&This->node, riid, ppvObject))
855     {
856         return *ppvObject ? S_OK : E_NOINTERFACE;
857     }
858     else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
859     {
860         *ppvObject = &This->IConnectionPointContainer_iface;
861     }
862     else
863     {
864         TRACE("interface %s not implemented\n", debugstr_guid(riid));
865         return E_NOINTERFACE;
866     }
867
868     IUnknown_AddRef((IUnknown*)*ppvObject);
869
870     return S_OK;
871 }
872
873 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
874 {
875     domdoc *This = impl_from_IXMLDOMDocument3( iface );
876     ULONG ref = InterlockedIncrement( &This->ref );
877     TRACE("(%p)->(%d)\n", This, ref );
878     return ref;
879 }
880
881 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
882 {
883     domdoc *This = impl_from_IXMLDOMDocument3( iface );
884     LONG ref = InterlockedDecrement( &This->ref );
885
886     TRACE("(%p)->(%d)\n", This, ref );
887
888     if ( ref == 0 )
889     {
890         int eid;
891
892         if(This->bsc)
893             detach_bsc(This->bsc);
894
895         if (This->site)
896             IUnknown_Release( This->site );
897         destroy_xmlnode(&This->node);
898         if (This->stream)
899             IStream_Release(This->stream);
900
901         for (eid = 0; eid < EVENTID_LAST; eid++)
902             if (This->events[eid]) IDispatch_Release(This->events[eid]);
903
904         heap_free(This);
905     }
906
907     return ref;
908 }
909
910 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
911 {
912     domdoc *This = impl_from_IXMLDOMDocument3( iface );
913     return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
914 }
915
916 static HRESULT WINAPI domdoc_GetTypeInfo(
917     IXMLDOMDocument3 *iface,
918     UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
919 {
920     domdoc *This = impl_from_IXMLDOMDocument3( iface );
921     return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
922 }
923
924 static HRESULT WINAPI domdoc_GetIDsOfNames(
925     IXMLDOMDocument3 *iface,
926     REFIID riid,
927     LPOLESTR* rgszNames,
928     UINT cNames,
929     LCID lcid,
930     DISPID* rgDispId)
931 {
932     domdoc *This = impl_from_IXMLDOMDocument3( iface );
933     return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
934         riid, rgszNames, cNames, lcid, rgDispId);
935 }
936
937 static HRESULT WINAPI domdoc_Invoke(
938     IXMLDOMDocument3 *iface,
939     DISPID dispIdMember,
940     REFIID riid,
941     LCID lcid,
942     WORD wFlags,
943     DISPPARAMS* pDispParams,
944     VARIANT* pVarResult,
945     EXCEPINFO* pExcepInfo,
946     UINT* puArgErr)
947 {
948     domdoc *This = impl_from_IXMLDOMDocument3( iface );
949     return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
950         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
951 }
952
953 static HRESULT WINAPI domdoc_get_nodeName(
954     IXMLDOMDocument3 *iface,
955     BSTR* name )
956 {
957     domdoc *This = impl_from_IXMLDOMDocument3( iface );
958
959     static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
960
961     TRACE("(%p)->(%p)\n", This, name);
962
963     return return_bstr(documentW, name);
964 }
965
966
967 static HRESULT WINAPI domdoc_get_nodeValue(
968     IXMLDOMDocument3 *iface,
969     VARIANT* value )
970 {
971     domdoc *This = impl_from_IXMLDOMDocument3( iface );
972
973     TRACE("(%p)->(%p)\n", This, value);
974
975     if(!value)
976         return E_INVALIDARG;
977
978     V_VT(value) = VT_NULL;
979     V_BSTR(value) = NULL; /* tests show that we should do this */
980     return S_FALSE;
981 }
982
983
984 static HRESULT WINAPI domdoc_put_nodeValue(
985     IXMLDOMDocument3 *iface,
986     VARIANT value)
987 {
988     domdoc *This = impl_from_IXMLDOMDocument3( iface );
989     TRACE("(%p)->(v%d)\n", This, V_VT(&value));
990     return E_FAIL;
991 }
992
993
994 static HRESULT WINAPI domdoc_get_nodeType(
995     IXMLDOMDocument3 *iface,
996     DOMNodeType* type )
997 {
998     domdoc *This = impl_from_IXMLDOMDocument3( iface );
999
1000     TRACE("(%p)->(%p)\n", This, type);
1001
1002     *type = NODE_DOCUMENT;
1003     return S_OK;
1004 }
1005
1006
1007 static HRESULT WINAPI domdoc_get_parentNode(
1008     IXMLDOMDocument3 *iface,
1009     IXMLDOMNode** parent )
1010 {
1011     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1012
1013     TRACE("(%p)->(%p)\n", This, parent);
1014
1015     return node_get_parent(&This->node, parent);
1016 }
1017
1018
1019 static HRESULT WINAPI domdoc_get_childNodes(
1020     IXMLDOMDocument3 *iface,
1021     IXMLDOMNodeList** childList )
1022 {
1023     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1024
1025     TRACE("(%p)->(%p)\n", This, childList);
1026
1027     return node_get_child_nodes(&This->node, childList);
1028 }
1029
1030
1031 static HRESULT WINAPI domdoc_get_firstChild(
1032     IXMLDOMDocument3 *iface,
1033     IXMLDOMNode** firstChild )
1034 {
1035     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1036
1037     TRACE("(%p)->(%p)\n", This, firstChild);
1038
1039     return node_get_first_child(&This->node, firstChild);
1040 }
1041
1042
1043 static HRESULT WINAPI domdoc_get_lastChild(
1044     IXMLDOMDocument3 *iface,
1045     IXMLDOMNode** lastChild )
1046 {
1047     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1048
1049     TRACE("(%p)->(%p)\n", This, lastChild);
1050
1051     return node_get_last_child(&This->node, lastChild);
1052 }
1053
1054
1055 static HRESULT WINAPI domdoc_get_previousSibling(
1056     IXMLDOMDocument3 *iface,
1057     IXMLDOMNode** previousSibling )
1058 {
1059     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1060
1061     TRACE("(%p)->(%p)\n", This, previousSibling);
1062
1063     return return_null_node(previousSibling);
1064 }
1065
1066
1067 static HRESULT WINAPI domdoc_get_nextSibling(
1068     IXMLDOMDocument3 *iface,
1069     IXMLDOMNode** nextSibling )
1070 {
1071     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1072
1073     TRACE("(%p)->(%p)\n", This, nextSibling);
1074
1075     return return_null_node(nextSibling);
1076 }
1077
1078
1079 static HRESULT WINAPI domdoc_get_attributes(
1080     IXMLDOMDocument3 *iface,
1081     IXMLDOMNamedNodeMap** attributeMap )
1082 {
1083     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1084
1085     TRACE("(%p)->(%p)\n", This, attributeMap);
1086
1087     return return_null_ptr((void**)attributeMap);
1088 }
1089
1090
1091 static HRESULT WINAPI domdoc_insertBefore(
1092     IXMLDOMDocument3 *iface,
1093     IXMLDOMNode* newChild,
1094     VARIANT refChild,
1095     IXMLDOMNode** outNewChild )
1096 {
1097     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1098
1099     TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1100
1101     return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1102 }
1103
1104
1105 static HRESULT WINAPI domdoc_replaceChild(
1106     IXMLDOMDocument3 *iface,
1107     IXMLDOMNode* newChild,
1108     IXMLDOMNode* oldChild,
1109     IXMLDOMNode** outOldChild)
1110 {
1111     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1112
1113     TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1114
1115     return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1116 }
1117
1118
1119 static HRESULT WINAPI domdoc_removeChild(
1120     IXMLDOMDocument3 *iface,
1121     IXMLDOMNode  *child,
1122     IXMLDOMNode **oldChild)
1123 {
1124     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1125     TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1126     return node_remove_child(&This->node, child, oldChild);
1127 }
1128
1129
1130 static HRESULT WINAPI domdoc_appendChild(
1131     IXMLDOMDocument3 *iface,
1132     IXMLDOMNode  *child,
1133     IXMLDOMNode **outChild)
1134 {
1135     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1136     TRACE("(%p)->(%p %p)\n", This, child, outChild);
1137     return node_append_child(&This->node, child, outChild);
1138 }
1139
1140
1141 static HRESULT WINAPI domdoc_hasChildNodes(
1142     IXMLDOMDocument3 *iface,
1143     VARIANT_BOOL *ret)
1144 {
1145     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1146     TRACE("(%p)->(%p)\n", This, ret);
1147     return node_has_childnodes(&This->node, ret);
1148 }
1149
1150
1151 static HRESULT WINAPI domdoc_get_ownerDocument(
1152     IXMLDOMDocument3 *iface,
1153     IXMLDOMDocument **doc)
1154 {
1155     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156     TRACE("(%p)->(%p)\n", This, doc);
1157     return node_get_owner_doc(&This->node, doc);
1158 }
1159
1160
1161 static HRESULT WINAPI domdoc_cloneNode(
1162     IXMLDOMDocument3 *iface,
1163     VARIANT_BOOL deep,
1164     IXMLDOMNode** outNode)
1165 {
1166     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1167     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1168     return node_clone( &This->node, deep, outNode );
1169 }
1170
1171
1172 static HRESULT WINAPI domdoc_get_nodeTypeString(
1173     IXMLDOMDocument3 *iface,
1174     BSTR *p)
1175 {
1176     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1177     static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1178
1179     TRACE("(%p)->(%p)\n", This, p);
1180
1181     return return_bstr(documentW, p);
1182 }
1183
1184
1185 static HRESULT WINAPI domdoc_get_text(
1186     IXMLDOMDocument3 *iface,
1187     BSTR *p)
1188 {
1189     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1190     TRACE("(%p)->(%p)\n", This, p);
1191     return node_get_text(&This->node, p);
1192 }
1193
1194
1195 static HRESULT WINAPI domdoc_put_text(
1196     IXMLDOMDocument3 *iface,
1197     BSTR text )
1198 {
1199     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1200     TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1201     return E_FAIL;
1202 }
1203
1204
1205 static HRESULT WINAPI domdoc_get_specified(
1206     IXMLDOMDocument3 *iface,
1207     VARIANT_BOOL* isSpecified )
1208 {
1209     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1211     *isSpecified = VARIANT_TRUE;
1212     return S_OK;
1213 }
1214
1215
1216 static HRESULT WINAPI domdoc_get_definition(
1217     IXMLDOMDocument3 *iface,
1218     IXMLDOMNode** definitionNode )
1219 {
1220     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1221     FIXME("(%p)->(%p)\n", This, definitionNode);
1222     return E_NOTIMPL;
1223 }
1224
1225
1226 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1227     IXMLDOMDocument3 *iface,
1228     VARIANT* v )
1229 {
1230     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1231     TRACE("(%p)->(%p)\n", This, v);
1232     return return_null_var(v);
1233 }
1234
1235 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1236     IXMLDOMDocument3 *iface,
1237     VARIANT typedValue )
1238 {
1239     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1240     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1241     return E_NOTIMPL;
1242 }
1243
1244
1245 static HRESULT WINAPI domdoc_get_dataType(
1246     IXMLDOMDocument3 *iface,
1247     VARIANT* typename )
1248 {
1249     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1250     TRACE("(%p)->(%p)\n", This, typename);
1251     return return_null_var( typename );
1252 }
1253
1254
1255 static HRESULT WINAPI domdoc_put_dataType(
1256     IXMLDOMDocument3 *iface,
1257     BSTR dataTypeName )
1258 {
1259     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1260
1261     FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1262
1263     if(!dataTypeName)
1264         return E_INVALIDARG;
1265
1266     return E_FAIL;
1267 }
1268
1269 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1270 {
1271     return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1272 }
1273
1274 static HRESULT WINAPI domdoc_get_xml(
1275     IXMLDOMDocument3 *iface,
1276     BSTR* p)
1277 {
1278     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279     xmlSaveCtxtPtr ctxt;
1280     xmlBufferPtr buf;
1281     int options;
1282     long ret;
1283
1284     TRACE("(%p)->(%p)\n", This, p);
1285
1286     if(!p)
1287         return E_INVALIDARG;
1288
1289     *p = NULL;
1290
1291     buf = xmlBufferCreate();
1292     if(!buf)
1293         return E_OUTOFMEMORY;
1294
1295     options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1296     ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1297
1298     if(!ctxt)
1299     {
1300         xmlBufferFree(buf);
1301         return E_OUTOFMEMORY;
1302     }
1303
1304     ret = xmlSaveDoc(ctxt, get_doc(This));
1305     /* flushes on close */
1306     xmlSaveClose(ctxt);
1307
1308     TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1309     if(ret != -1 && xmlBufferLength(buf) > 0)
1310     {
1311         BSTR content;
1312
1313         content = bstr_from_xmlChar(xmlBufferContent(buf));
1314         content = EnsureCorrectEOL(content);
1315
1316         *p = content;
1317     }
1318     else
1319     {
1320         *p = SysAllocStringLen(NULL, 0);
1321     }
1322
1323     xmlBufferFree(buf);
1324
1325     return *p ? S_OK : E_OUTOFMEMORY;
1326 }
1327
1328
1329 static HRESULT WINAPI domdoc_transformNode(
1330     IXMLDOMDocument3 *iface,
1331     IXMLDOMNode *node,
1332     BSTR *p)
1333 {
1334     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1335     TRACE("(%p)->(%p %p)\n", This, node, p);
1336     return node_transform_node(&This->node, node, p);
1337 }
1338
1339
1340 static HRESULT WINAPI domdoc_selectNodes(
1341     IXMLDOMDocument3 *iface,
1342     BSTR p,
1343     IXMLDOMNodeList **outList)
1344 {
1345     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1346     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1347     return node_select_nodes(&This->node, p, outList);
1348 }
1349
1350
1351 static HRESULT WINAPI domdoc_selectSingleNode(
1352     IXMLDOMDocument3 *iface,
1353     BSTR p,
1354     IXMLDOMNode **outNode)
1355 {
1356     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1357     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1358     return node_select_singlenode(&This->node, p, outNode);
1359 }
1360
1361
1362 static HRESULT WINAPI domdoc_get_parsed(
1363     IXMLDOMDocument3 *iface,
1364     VARIANT_BOOL* isParsed )
1365 {
1366     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1367     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1368     *isParsed = VARIANT_TRUE;
1369     return S_OK;
1370 }
1371
1372
1373 static HRESULT WINAPI domdoc_get_namespaceURI(
1374     IXMLDOMDocument3 *iface,
1375     BSTR* namespaceURI )
1376 {
1377     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1378     TRACE("(%p)->(%p)\n", This, namespaceURI);
1379     return node_get_namespaceURI(&This->node, namespaceURI);
1380 }
1381
1382
1383 static HRESULT WINAPI domdoc_get_prefix(
1384     IXMLDOMDocument3 *iface,
1385     BSTR* prefix )
1386 {
1387     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1388     TRACE("(%p)->(%p)\n", This, prefix);
1389     return return_null_bstr( prefix );
1390 }
1391
1392
1393 static HRESULT WINAPI domdoc_get_baseName(
1394     IXMLDOMDocument3 *iface,
1395     BSTR* name )
1396 {
1397     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1398     TRACE("(%p)->(%p)\n", This, name);
1399     return return_null_bstr( name );
1400 }
1401
1402
1403 static HRESULT WINAPI domdoc_transformNodeToObject(
1404     IXMLDOMDocument3 *iface,
1405     IXMLDOMNode* stylesheet,
1406     VARIANT outputObject)
1407 {
1408     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409     FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1410     return E_NOTIMPL;
1411 }
1412
1413
1414 static HRESULT WINAPI domdoc_get_doctype(
1415     IXMLDOMDocument3 *iface,
1416     IXMLDOMDocumentType** doctype )
1417 {
1418     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1419     IXMLDOMNode *node;
1420     xmlDtdPtr dtd;
1421     HRESULT hr;
1422
1423     TRACE("(%p)->(%p)\n", This, doctype);
1424
1425     if (!doctype) return E_INVALIDARG;
1426
1427     *doctype = NULL;
1428
1429     dtd = xmlGetIntSubset(get_doc(This));
1430     if (!dtd) return S_FALSE;
1431
1432     node = create_node((xmlNodePtr)dtd);
1433     if (!node) return S_FALSE;
1434
1435     hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1436     IXMLDOMNode_Release(node);
1437
1438     return hr;
1439 }
1440
1441
1442 static HRESULT WINAPI domdoc_get_implementation(
1443     IXMLDOMDocument3 *iface,
1444     IXMLDOMImplementation** impl )
1445 {
1446     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1447
1448     TRACE("(%p)->(%p)\n", This, impl);
1449
1450     if(!impl)
1451         return E_INVALIDARG;
1452
1453     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1454
1455     return S_OK;
1456 }
1457
1458 static HRESULT WINAPI domdoc_get_documentElement(
1459     IXMLDOMDocument3 *iface,
1460     IXMLDOMElement** DOMElement )
1461 {
1462     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1463     IXMLDOMNode *element_node;
1464     xmlNodePtr root;
1465     HRESULT hr;
1466
1467     TRACE("(%p)->(%p)\n", This, DOMElement);
1468
1469     if(!DOMElement)
1470         return E_INVALIDARG;
1471
1472     *DOMElement = NULL;
1473
1474     root = xmlDocGetRootElement( get_doc(This) );
1475     if ( !root )
1476         return S_FALSE;
1477
1478     element_node = create_node( root );
1479     if(!element_node) return S_FALSE;
1480
1481     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1482     IXMLDOMNode_Release(element_node);
1483
1484     return hr;
1485 }
1486
1487
1488 static HRESULT WINAPI domdoc_put_documentElement(
1489     IXMLDOMDocument3 *iface,
1490     IXMLDOMElement* DOMElement )
1491 {
1492     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1493     IXMLDOMNode *elementNode;
1494     xmlNodePtr oldRoot;
1495     xmlnode *xmlNode;
1496     HRESULT hr;
1497
1498     TRACE("(%p)->(%p)\n", This, DOMElement);
1499
1500     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1501     if(FAILED(hr))
1502         return hr;
1503
1504     xmlNode = get_node_obj( elementNode );
1505     if(!xmlNode) return E_FAIL;
1506
1507     if(!xmlNode->node->parent)
1508         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1509             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1510
1511     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1512     IXMLDOMNode_Release( elementNode );
1513
1514     if(oldRoot)
1515         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1516
1517     return S_OK;
1518 }
1519
1520
1521 static HRESULT WINAPI domdoc_createElement(
1522     IXMLDOMDocument3 *iface,
1523     BSTR tagname,
1524     IXMLDOMElement** element )
1525 {
1526     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1527     IXMLDOMNode *node;
1528     VARIANT type;
1529     HRESULT hr;
1530
1531     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1532
1533     if (!element || !tagname) return E_INVALIDARG;
1534
1535     V_VT(&type) = VT_I1;
1536     V_I1(&type) = NODE_ELEMENT;
1537
1538     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1539     if (hr == S_OK)
1540     {
1541         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1542         IXMLDOMNode_Release(node);
1543     }
1544
1545     return hr;
1546 }
1547
1548
1549 static HRESULT WINAPI domdoc_createDocumentFragment(
1550     IXMLDOMDocument3 *iface,
1551     IXMLDOMDocumentFragment** frag )
1552 {
1553     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1554     IXMLDOMNode *node;
1555     VARIANT type;
1556     HRESULT hr;
1557
1558     TRACE("(%p)->(%p)\n", This, frag);
1559
1560     if (!frag) return E_INVALIDARG;
1561
1562     *frag = NULL;
1563
1564     V_VT(&type) = VT_I1;
1565     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1566
1567     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1568     if (hr == S_OK)
1569     {
1570         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1571         IXMLDOMNode_Release(node);
1572     }
1573
1574     return hr;
1575 }
1576
1577
1578 static HRESULT WINAPI domdoc_createTextNode(
1579     IXMLDOMDocument3 *iface,
1580     BSTR data,
1581     IXMLDOMText** text )
1582 {
1583     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1584     IXMLDOMNode *node;
1585     VARIANT type;
1586     HRESULT hr;
1587
1588     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1589
1590     if (!text) return E_INVALIDARG;
1591
1592     *text = NULL;
1593
1594     V_VT(&type) = VT_I1;
1595     V_I1(&type) = NODE_TEXT;
1596
1597     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1598     if (hr == S_OK)
1599     {
1600         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1601         IXMLDOMNode_Release(node);
1602         hr = IXMLDOMText_put_data(*text, data);
1603     }
1604
1605     return hr;
1606 }
1607
1608
1609 static HRESULT WINAPI domdoc_createComment(
1610     IXMLDOMDocument3 *iface,
1611     BSTR data,
1612     IXMLDOMComment** comment )
1613 {
1614     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1615     VARIANT type;
1616     HRESULT hr;
1617     IXMLDOMNode *node;
1618
1619     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1620
1621     if (!comment) return E_INVALIDARG;
1622
1623     *comment = NULL;
1624
1625     V_VT(&type) = VT_I1;
1626     V_I1(&type) = NODE_COMMENT;
1627
1628     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1629     if (hr == S_OK)
1630     {
1631         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1632         IXMLDOMNode_Release(node);
1633         hr = IXMLDOMComment_put_data(*comment, data);
1634     }
1635
1636     return hr;
1637 }
1638
1639
1640 static HRESULT WINAPI domdoc_createCDATASection(
1641     IXMLDOMDocument3 *iface,
1642     BSTR data,
1643     IXMLDOMCDATASection** cdata )
1644 {
1645     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1646     IXMLDOMNode *node;
1647     VARIANT type;
1648     HRESULT hr;
1649
1650     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1651
1652     if (!cdata) return E_INVALIDARG;
1653
1654     *cdata = NULL;
1655
1656     V_VT(&type) = VT_I1;
1657     V_I1(&type) = NODE_CDATA_SECTION;
1658
1659     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1660     if (hr == S_OK)
1661     {
1662         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1663         IXMLDOMNode_Release(node);
1664         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1665     }
1666
1667     return hr;
1668 }
1669
1670
1671 static HRESULT WINAPI domdoc_createProcessingInstruction(
1672     IXMLDOMDocument3 *iface,
1673     BSTR target,
1674     BSTR data,
1675     IXMLDOMProcessingInstruction** pi )
1676 {
1677     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1678     IXMLDOMNode *node;
1679     VARIANT type;
1680     HRESULT hr;
1681
1682     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1683
1684     if (!pi) return E_INVALIDARG;
1685
1686     *pi = NULL;
1687
1688     V_VT(&type) = VT_I1;
1689     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1690
1691     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1692     if (hr == S_OK)
1693     {
1694         xmlnode *node_obj;
1695
1696         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1697         node_obj = get_node_obj(node);
1698         hr = node_set_content(node_obj, data);
1699
1700         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1701         IXMLDOMNode_Release(node);
1702     }
1703
1704     return hr;
1705 }
1706
1707
1708 static HRESULT WINAPI domdoc_createAttribute(
1709     IXMLDOMDocument3 *iface,
1710     BSTR name,
1711     IXMLDOMAttribute** attribute )
1712 {
1713     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1714     IXMLDOMNode *node;
1715     VARIANT type;
1716     HRESULT hr;
1717
1718     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1719
1720     if (!attribute || !name) return E_INVALIDARG;
1721
1722     V_VT(&type) = VT_I1;
1723     V_I1(&type) = NODE_ATTRIBUTE;
1724
1725     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1726     if (hr == S_OK)
1727     {
1728         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1729         IXMLDOMNode_Release(node);
1730     }
1731
1732     return hr;
1733 }
1734
1735
1736 static HRESULT WINAPI domdoc_createEntityReference(
1737     IXMLDOMDocument3 *iface,
1738     BSTR name,
1739     IXMLDOMEntityReference** entityref )
1740 {
1741     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1742     IXMLDOMNode *node;
1743     VARIANT type;
1744     HRESULT hr;
1745
1746     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1747
1748     if (!entityref) return E_INVALIDARG;
1749
1750     *entityref = NULL;
1751
1752     V_VT(&type) = VT_I1;
1753     V_I1(&type) = NODE_ENTITY_REFERENCE;
1754
1755     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1756     if (hr == S_OK)
1757     {
1758         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1759         IXMLDOMNode_Release(node);
1760     }
1761
1762     return hr;
1763 }
1764
1765 xmlChar* tagName_to_XPath(const BSTR tagName)
1766 {
1767     xmlChar *query, *tmp;
1768     static const xmlChar mod_pre[] = "*[local-name()='";
1769     static const xmlChar mod_post[] = "']";
1770     static const xmlChar prefix[] = "descendant::";
1771     const WCHAR *tokBegin, *tokEnd;
1772     int len;
1773
1774     query = xmlStrdup(prefix);
1775
1776     tokBegin = tagName;
1777     while (tokBegin && *tokBegin)
1778     {
1779         switch (*tokBegin)
1780         {
1781         case '/':
1782             query = xmlStrcat(query, BAD_CAST "/");
1783             ++tokBegin;
1784             break;
1785         case '*':
1786             query = xmlStrcat(query, BAD_CAST "*");
1787             ++tokBegin;
1788             break;
1789         default:
1790             query = xmlStrcat(query, mod_pre);
1791             tokEnd = tokBegin;
1792             while (*tokEnd && *tokEnd != '/')
1793                 ++tokEnd;
1794             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1795             tmp = xmlMalloc(len);
1796             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1797             query = xmlStrncat(query, tmp, len);
1798             xmlFree(tmp);
1799             tokBegin = tokEnd;
1800             query = xmlStrcat(query, mod_post);
1801         }
1802     }
1803
1804     return query;
1805 }
1806
1807 static HRESULT WINAPI domdoc_getElementsByTagName(
1808     IXMLDOMDocument3 *iface,
1809     BSTR tagName,
1810     IXMLDOMNodeList** resultList )
1811 {
1812     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1813     xmlChar *query;
1814     HRESULT hr;
1815     BOOL XPath;
1816
1817     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1818
1819     if (!tagName || !resultList) return E_INVALIDARG;
1820
1821     XPath = This->properties->XPath;
1822     This->properties->XPath = TRUE;
1823     query = tagName_to_XPath(tagName);
1824     hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1825     xmlFree(query);
1826     This->properties->XPath = XPath;
1827
1828     return hr;
1829 }
1830
1831 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1832 {
1833     VARIANT tmp;
1834     HRESULT hr;
1835
1836     VariantInit(&tmp);
1837     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1838     if(FAILED(hr))
1839         return E_INVALIDARG;
1840
1841     *type = V_I4(&tmp);
1842
1843     return S_OK;
1844 }
1845
1846 static HRESULT WINAPI domdoc_createNode(
1847     IXMLDOMDocument3 *iface,
1848     VARIANT Type,
1849     BSTR name,
1850     BSTR namespaceURI,
1851     IXMLDOMNode** node )
1852 {
1853     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1854     DOMNodeType node_type;
1855     xmlNodePtr xmlnode;
1856     xmlChar *xml_name, *href;
1857     HRESULT hr;
1858
1859     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1860
1861     if(!node) return E_INVALIDARG;
1862
1863     hr = get_node_type(Type, &node_type);
1864     if(FAILED(hr)) return hr;
1865
1866     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1867         FIXME("nodes with namespaces currently not supported.\n");
1868
1869     TRACE("node_type %d\n", node_type);
1870
1871     /* exit earlier for types that need name */
1872     switch(node_type)
1873     {
1874     case NODE_ELEMENT:
1875     case NODE_ATTRIBUTE:
1876     case NODE_ENTITY_REFERENCE:
1877     case NODE_PROCESSING_INSTRUCTION:
1878         if (!name || *name == 0) return E_FAIL;
1879         break;
1880     default:
1881         break;
1882     }
1883
1884     xml_name = xmlchar_from_wchar(name);
1885     /* prevent empty href to be allocated */
1886     href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1887
1888     switch(node_type)
1889     {
1890     case NODE_ELEMENT:
1891     {
1892         xmlChar *local, *prefix;
1893
1894         local = xmlSplitQName2(xml_name, &prefix);
1895
1896         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1897
1898         /* allow to create default namespace xmlns= */
1899         if (local || (href && *href))
1900         {
1901             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1902             xmlSetNs(xmlnode, ns);
1903         }
1904
1905         xmlFree(local);
1906         xmlFree(prefix);
1907
1908         break;
1909     }
1910     case NODE_ATTRIBUTE:
1911         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1912         break;
1913     case NODE_TEXT:
1914         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1915         break;
1916     case NODE_CDATA_SECTION:
1917         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1918         break;
1919     case NODE_ENTITY_REFERENCE:
1920         xmlnode = xmlNewReference(get_doc(This), xml_name);
1921         break;
1922     case NODE_PROCESSING_INSTRUCTION:
1923 #ifdef HAVE_XMLNEWDOCPI
1924         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1925 #else
1926         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1927         xmlnode = NULL;
1928 #endif
1929         break;
1930     case NODE_COMMENT:
1931         xmlnode = xmlNewDocComment(get_doc(This), NULL);
1932         break;
1933     case NODE_DOCUMENT_FRAGMENT:
1934         xmlnode = xmlNewDocFragment(get_doc(This));
1935         break;
1936     /* unsupported types */
1937     case NODE_DOCUMENT:
1938     case NODE_DOCUMENT_TYPE:
1939     case NODE_ENTITY:
1940     case NODE_NOTATION:
1941         heap_free(xml_name);
1942         return E_INVALIDARG;
1943     default:
1944         FIXME("unhandled node type %d\n", node_type);
1945         xmlnode = NULL;
1946         break;
1947     }
1948
1949     *node = create_node(xmlnode);
1950     heap_free(xml_name);
1951     heap_free(href);
1952
1953     if(*node)
1954     {
1955         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1956         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1957         return S_OK;
1958     }
1959
1960     return E_FAIL;
1961 }
1962
1963 static HRESULT WINAPI domdoc_nodeFromID(
1964     IXMLDOMDocument3 *iface,
1965     BSTR idString,
1966     IXMLDOMNode** node )
1967 {
1968     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1969     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1970     return E_NOTIMPL;
1971 }
1972
1973 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1974 {
1975     domdoc *This = obj;
1976     xmlDocPtr xmldoc;
1977
1978     xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1979     if(xmldoc) {
1980         xmldoc->_private = create_priv();
1981         return attach_xmldoc(This, xmldoc);
1982     }
1983
1984     return S_OK;
1985 }
1986
1987 static HRESULT doread( domdoc *This, LPWSTR filename )
1988 {
1989     bsc_t *bsc;
1990     HRESULT hr;
1991
1992     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1993     if(FAILED(hr))
1994         return hr;
1995
1996     if(This->bsc) {
1997         hr = detach_bsc(This->bsc);
1998         if(FAILED(hr))
1999             return hr;
2000     }
2001
2002     This->bsc = bsc;
2003     return S_OK;
2004 }
2005
2006 static HRESULT WINAPI domdoc_load(
2007     IXMLDOMDocument3 *iface,
2008     VARIANT source,
2009     VARIANT_BOOL* isSuccessful )
2010 {
2011     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2012     LPWSTR filename = NULL;
2013     HRESULT hr = S_FALSE;
2014     IXMLDOMDocument3 *pNewDoc = NULL;
2015     IStream *pStream = NULL;
2016     xmlDocPtr xmldoc;
2017
2018     TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2019
2020     if (!isSuccessful)
2021         return E_POINTER;
2022     *isSuccessful = VARIANT_FALSE;
2023
2024     assert( &This->node );
2025
2026     switch( V_VT(&source) )
2027     {
2028     case VT_BSTR:
2029         filename = V_BSTR(&source);
2030         break;
2031     case VT_BSTR|VT_BYREF:
2032         if (!V_BSTRREF(&source)) return E_INVALIDARG;
2033         filename = *V_BSTRREF(&source);
2034         break;
2035     case VT_ARRAY|VT_UI1:
2036         {
2037             SAFEARRAY *psa = V_ARRAY(&source);
2038             char *str;
2039             LONG len;
2040             UINT dim = SafeArrayGetDim(psa);
2041
2042             switch (dim)
2043             {
2044             case 0:
2045                 ERR("SAFEARRAY == NULL\n");
2046                 hr = This->error = E_INVALIDARG;
2047                 break;
2048             case 1:
2049                 /* Only takes UTF-8 strings.
2050                  * NOT NULL-terminated. */
2051                 SafeArrayAccessData(psa, (void**)&str);
2052                 SafeArrayGetUBound(psa, 1, &len);
2053
2054                 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2055                 {
2056                     hr = This->error = S_OK;
2057                     *isSuccessful = VARIANT_TRUE;
2058                     TRACE("parsed document %p\n", xmldoc);
2059                 }
2060                 else
2061                 {
2062                     This->error = E_FAIL;
2063                     TRACE("failed to parse document\n");
2064                 }
2065
2066                 SafeArrayUnaccessData(psa);
2067
2068                 if(xmldoc)
2069                 {
2070                     xmldoc->_private = create_priv();
2071                     return attach_xmldoc(This, xmldoc);
2072                 }
2073                 break;
2074             default:
2075                 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2076                 hr = This->error = E_NOTIMPL;
2077             }
2078         }
2079         break;
2080     case VT_UNKNOWN:
2081         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2082         if(hr == S_OK)
2083         {
2084             if(pNewDoc)
2085             {
2086                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2087                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2088                 hr = attach_xmldoc(This, xmldoc);
2089
2090                 if(SUCCEEDED(hr))
2091                     *isSuccessful = VARIANT_TRUE;
2092
2093                 return hr;
2094             }
2095         }
2096         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2097         if(hr == S_OK)
2098         {
2099             IPersistStream *pDocStream;
2100             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2101             if(hr == S_OK)
2102             {
2103                 hr = IPersistStream_Load(pDocStream, pStream);
2104                 IStream_Release(pStream);
2105                 if(hr == S_OK)
2106                 {
2107                     *isSuccessful = VARIANT_TRUE;
2108
2109                     TRACE("Using IStream to load Document\n");
2110                     return S_OK;
2111                 }
2112                 else
2113                 {
2114                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2115                 }
2116             }
2117             else
2118             {
2119                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2120             }
2121         }
2122         else
2123         {
2124             /* ISequentialStream */
2125             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2126         }
2127         break;
2128      default:
2129             FIXME("VT type not supported (%d)\n", V_VT(&source));
2130     }
2131
2132     if ( filename )
2133     {
2134         hr = doread( This, filename );
2135
2136         if ( FAILED(hr) )
2137             This->error = E_FAIL;
2138         else
2139         {
2140             hr = This->error = S_OK;
2141             *isSuccessful = VARIANT_TRUE;
2142         }
2143     }
2144
2145     if(!filename || FAILED(hr)) {
2146         xmldoc = xmlNewDoc(NULL);
2147         xmldoc->_private = create_priv();
2148         hr = attach_xmldoc(This, xmldoc);
2149         if(SUCCEEDED(hr))
2150             hr = S_FALSE;
2151     }
2152
2153     TRACE("ret (%d)\n", hr);
2154
2155     return hr;
2156 }
2157
2158
2159 static HRESULT WINAPI domdoc_get_readyState(
2160     IXMLDOMDocument3 *iface,
2161     LONG *value )
2162 {
2163     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2164     FIXME("stub! (%p)->(%p)\n", This, value);
2165
2166     if (!value)
2167         return E_INVALIDARG;
2168
2169     *value = READYSTATE_COMPLETE;
2170     return S_OK;
2171 }
2172
2173
2174 static HRESULT WINAPI domdoc_get_parseError(
2175     IXMLDOMDocument3 *iface,
2176     IXMLDOMParseError** errorObj )
2177 {
2178     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2179     static const WCHAR err[] = {'e','r','r','o','r',0};
2180     BSTR error_string = NULL;
2181
2182     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2183
2184     if(This->error)
2185         error_string = SysAllocString(err);
2186
2187     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2188     if(!*errorObj) return E_OUTOFMEMORY;
2189     return S_OK;
2190 }
2191
2192
2193 static HRESULT WINAPI domdoc_get_url(
2194     IXMLDOMDocument3 *iface,
2195     BSTR* urlString )
2196 {
2197     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2198     FIXME("(%p)->(%p)\n", This, urlString);
2199     return E_NOTIMPL;
2200 }
2201
2202
2203 static HRESULT WINAPI domdoc_get_async(
2204     IXMLDOMDocument3 *iface,
2205     VARIANT_BOOL* isAsync )
2206 {
2207     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2208
2209     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2210     *isAsync = This->async;
2211     return S_OK;
2212 }
2213
2214
2215 static HRESULT WINAPI domdoc_put_async(
2216     IXMLDOMDocument3 *iface,
2217     VARIANT_BOOL isAsync )
2218 {
2219     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2220
2221     TRACE("(%p)->(%d)\n", This, isAsync);
2222     This->async = isAsync;
2223     return S_OK;
2224 }
2225
2226
2227 static HRESULT WINAPI domdoc_abort(
2228     IXMLDOMDocument3 *iface )
2229 {
2230     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2231     FIXME("%p\n", This);
2232     return E_NOTIMPL;
2233 }
2234
2235
2236 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2237 static HRESULT WINAPI domdoc_loadXML(
2238     IXMLDOMDocument3 *iface,
2239     BSTR bstrXML,
2240     VARIANT_BOOL* isSuccessful )
2241 {
2242     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2243     xmlDocPtr xmldoc = NULL;
2244     HRESULT hr = S_FALSE, hr2;
2245
2246     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2247
2248     assert ( &This->node );
2249
2250     if ( isSuccessful )
2251     {
2252         *isSuccessful = VARIANT_FALSE;
2253
2254         if ( bstrXML )
2255         {
2256             xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2257             if ( !xmldoc )
2258             {
2259                 This->error = E_FAIL;
2260                 TRACE("failed to parse document\n");
2261             }
2262             else
2263             {
2264                 hr = This->error = S_OK;
2265                 *isSuccessful = VARIANT_TRUE;
2266                 TRACE("parsed document %p\n", xmldoc);
2267             }
2268         }
2269     }
2270     if(!xmldoc)
2271         xmldoc = xmlNewDoc(NULL);
2272
2273     xmldoc->_private = create_priv();
2274
2275     hr2 = attach_xmldoc(This, xmldoc);
2276     if( FAILED(hr2) )
2277         hr = hr2;
2278
2279     return hr;
2280 }
2281
2282 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2283 {
2284     DWORD written = -1;
2285
2286     if(!WriteFile(ctx, buffer, len, &written, NULL))
2287     {
2288         WARN("write error\n");
2289         return -1;
2290     }
2291     else
2292         return written;
2293 }
2294
2295 static int XMLCALL domdoc_save_closecallback(void *ctx)
2296 {
2297     return CloseHandle(ctx) ? 0 : -1;
2298 }
2299
2300 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2301 {
2302     ULONG written = 0;
2303     HRESULT hr;
2304
2305     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2306     if (hr != S_OK)
2307     {
2308         WARN("stream write error: 0x%08x\n", hr);
2309         return -1;
2310     }
2311     else
2312         return written;
2313 }
2314
2315 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2316 {
2317     IStream_Release((IStream*)ctx);
2318     return 0;
2319 }
2320
2321 static HRESULT WINAPI domdoc_save(
2322     IXMLDOMDocument3 *iface,
2323     VARIANT destination )
2324 {
2325     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2326     xmlSaveCtxtPtr ctx = NULL;
2327     xmlNodePtr xmldecl;
2328     HRESULT ret = S_OK;
2329
2330     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2331
2332     switch (V_VT(&destination))
2333     {
2334     case VT_UNKNOWN:
2335         {
2336             IUnknown *pUnk = V_UNKNOWN(&destination);
2337             IXMLDOMDocument3 *document;
2338             IStream *stream;
2339
2340             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2341             if(ret == S_OK)
2342             {
2343                 VARIANT_BOOL success;
2344                 BSTR xml;
2345
2346                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2347                 if(ret == S_OK)
2348                 {
2349                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2350                     SysFreeString(xml);
2351                 }
2352
2353                 IXMLDOMDocument3_Release(document);
2354                 return ret;
2355             }
2356
2357             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2358             if(ret == S_OK)
2359             {
2360                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2361                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2362
2363                 if(!ctx)
2364                 {
2365                     IStream_Release(stream);
2366                     return E_FAIL;
2367                 }
2368             }
2369         }
2370         break;
2371
2372     case VT_BSTR:
2373     case VT_BSTR | VT_BYREF:
2374         {
2375             /* save with file path */
2376             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2377                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2378             if( handle == INVALID_HANDLE_VALUE )
2379             {
2380                 WARN("failed to create file\n");
2381                 return E_FAIL;
2382             }
2383
2384             /* disable top XML declaration */
2385             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2386                               handle, NULL, XML_SAVE_NO_DECL);
2387             if (!ctx)
2388             {
2389                 CloseHandle(handle);
2390                 return E_FAIL;
2391             }
2392         }
2393         break;
2394
2395     default:
2396         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2397         return S_FALSE;
2398     }
2399
2400     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2401     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2402     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2403
2404     /* will release resources through close callback */
2405     xmlSaveClose(ctx);
2406
2407     return ret;
2408 }
2409
2410 static HRESULT WINAPI domdoc_get_validateOnParse(
2411     IXMLDOMDocument3 *iface,
2412     VARIANT_BOOL* isValidating )
2413 {
2414     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2415     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2416     *isValidating = This->validating;
2417     return S_OK;
2418 }
2419
2420
2421 static HRESULT WINAPI domdoc_put_validateOnParse(
2422     IXMLDOMDocument3 *iface,
2423     VARIANT_BOOL isValidating )
2424 {
2425     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2426     TRACE("(%p)->(%d)\n", This, isValidating);
2427     This->validating = isValidating;
2428     return S_OK;
2429 }
2430
2431
2432 static HRESULT WINAPI domdoc_get_resolveExternals(
2433     IXMLDOMDocument3 *iface,
2434     VARIANT_BOOL* isResolving )
2435 {
2436     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2437     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2438     *isResolving = This->resolving;
2439     return S_OK;
2440 }
2441
2442
2443 static HRESULT WINAPI domdoc_put_resolveExternals(
2444     IXMLDOMDocument3 *iface,
2445     VARIANT_BOOL isResolving )
2446 {
2447     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448     TRACE("(%p)->(%d)\n", This, isResolving);
2449     This->resolving = isResolving;
2450     return S_OK;
2451 }
2452
2453
2454 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2455     IXMLDOMDocument3 *iface,
2456     VARIANT_BOOL* isPreserving )
2457 {
2458     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2459     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2460     *isPreserving = This->properties->preserving;
2461     return S_OK;
2462 }
2463
2464
2465 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2466     IXMLDOMDocument3 *iface,
2467     VARIANT_BOOL isPreserving )
2468 {
2469     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2470     TRACE("(%p)->(%d)\n", This, isPreserving);
2471     This->properties->preserving = isPreserving;
2472     return S_OK;
2473 }
2474
2475
2476 static HRESULT WINAPI domdoc_put_onreadystatechange(
2477     IXMLDOMDocument3 *iface,
2478     VARIANT event )
2479 {
2480     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2481
2482     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2483     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2484 }
2485
2486
2487 static HRESULT WINAPI domdoc_put_onDataAvailable(
2488     IXMLDOMDocument3 *iface,
2489     VARIANT onDataAvailableSink )
2490 {
2491     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492     FIXME("%p\n", This);
2493     return E_NOTIMPL;
2494 }
2495
2496 static HRESULT WINAPI domdoc_put_onTransformNode(
2497     IXMLDOMDocument3 *iface,
2498     VARIANT onTransformNodeSink )
2499 {
2500     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2501     FIXME("%p\n", This);
2502     return E_NOTIMPL;
2503 }
2504
2505 static HRESULT WINAPI domdoc_get_namespaces(
2506     IXMLDOMDocument3* iface,
2507     IXMLDOMSchemaCollection** schemaCollection )
2508 {
2509     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2510     FIXME("(%p)->(%p)\n", This, schemaCollection);
2511     return E_NOTIMPL;
2512 }
2513
2514 static HRESULT WINAPI domdoc_get_schemas(
2515     IXMLDOMDocument3* iface,
2516     VARIANT* var1 )
2517 {
2518     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2519     HRESULT hr = S_FALSE;
2520     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2521
2522     TRACE("(%p)->(%p)\n", This, var1);
2523
2524     VariantInit(var1); /* Test shows we don't call VariantClear here */
2525     V_VT(var1) = VT_NULL;
2526
2527     if(cur_schema)
2528     {
2529         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2530         if(SUCCEEDED(hr))
2531             V_VT(var1) = VT_DISPATCH;
2532     }
2533     return hr;
2534 }
2535
2536 static HRESULT WINAPI domdoc_putref_schemas(
2537     IXMLDOMDocument3* iface,
2538     VARIANT var1)
2539 {
2540     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2541     HRESULT hr = E_FAIL;
2542     IXMLDOMSchemaCollection2* new_schema = NULL;
2543
2544     FIXME("(%p): semi-stub\n", This);
2545     switch(V_VT(&var1))
2546     {
2547     case VT_UNKNOWN:
2548         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2549         break;
2550
2551     case VT_DISPATCH:
2552         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2553         break;
2554
2555     case VT_NULL:
2556     case VT_EMPTY:
2557         hr = S_OK;
2558         break;
2559
2560     default:
2561         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2562     }
2563
2564     if(SUCCEEDED(hr))
2565     {
2566         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2567         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2568     }
2569
2570     return hr;
2571 }
2572
2573 static inline BOOL is_wellformed(xmlDocPtr doc)
2574 {
2575 #ifdef HAVE_XMLDOC_PROPERTIES
2576     return doc->properties & XML_DOC_WELLFORMED;
2577 #else
2578     /* Not a full check, but catches the worst violations */
2579     xmlNodePtr child;
2580     int root = 0;
2581
2582     for (child = doc->children; child != NULL; child = child->next)
2583     {
2584         switch (child->type)
2585         {
2586         case XML_ELEMENT_NODE:
2587             if (++root > 1)
2588                 return FALSE;
2589             break;
2590         case XML_TEXT_NODE:
2591         case XML_CDATA_SECTION_NODE:
2592             return FALSE;
2593             break;
2594         default:
2595             break;
2596         }
2597     }
2598
2599     return root == 1;
2600 #endif
2601 }
2602
2603 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2604 {
2605     va_list ap;
2606     va_start(ap, msg);
2607     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2608     va_end(ap);
2609 }
2610
2611 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2612 {
2613     va_list ap;
2614     va_start(ap, msg);
2615     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2616     va_end(ap);
2617 }
2618
2619 static HRESULT WINAPI domdoc_validateNode(
2620     IXMLDOMDocument3* iface,
2621     IXMLDOMNode* node,
2622     IXMLDOMParseError** err)
2623 {
2624     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2625     LONG state, err_code = 0;
2626     HRESULT hr = S_OK;
2627     int validated = 0;
2628
2629     TRACE("(%p)->(%p, %p)\n", This, node, err);
2630     domdoc_get_readyState(iface, &state);
2631     if (state != READYSTATE_COMPLETE)
2632     {
2633         if (err)
2634            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2635         return E_PENDING;
2636     }
2637
2638     if (!node)
2639     {
2640         if (err)
2641             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2642         return E_POINTER;
2643     }
2644
2645     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2646     {
2647         if (err)
2648             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2649         return E_FAIL;
2650     }
2651
2652     if (!is_wellformed(get_doc(This)))
2653     {
2654         ERR("doc not well-formed\n");
2655         if (err)
2656             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2657         return S_FALSE;
2658     }
2659
2660     /* DTD validation */
2661     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2662     {
2663         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2664         vctx->error = validate_error;
2665         vctx->warning = validate_warning;
2666         ++validated;
2667
2668         if (!((node == (IXMLDOMNode*)iface)?
2669               xmlValidateDocument(vctx, get_doc(This)) :
2670               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2671         {
2672             /* TODO: get a real error code here */
2673             TRACE("DTD validation failed\n");
2674             err_code = E_XML_INVALID;
2675             hr = S_FALSE;
2676         }
2677         xmlFreeValidCtxt(vctx);
2678     }
2679
2680     /* Schema validation */
2681     if (hr == S_OK && This->properties->schemaCache != NULL)
2682     {
2683
2684         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2685         if (SUCCEEDED(hr))
2686         {
2687             ++validated;
2688             /* TODO: get a real error code here */
2689             if (hr == S_OK)
2690             {
2691                 TRACE("schema validation succeeded\n");
2692             }
2693             else
2694             {
2695                 ERR("schema validation failed\n");
2696                 err_code = E_XML_INVALID;
2697             }
2698         }
2699         else
2700         {
2701             /* not really OK, just didn't find a schema for the ns */
2702             hr = S_OK;
2703         }
2704     }
2705
2706     if (!validated)
2707     {
2708         ERR("no DTD or schema found\n");
2709         err_code = E_XML_NODTD;
2710         hr = S_FALSE;
2711     }
2712
2713     if (err)
2714         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2715
2716     return hr;
2717 }
2718
2719 static HRESULT WINAPI domdoc_validate(
2720     IXMLDOMDocument3* iface,
2721     IXMLDOMParseError** err)
2722 {
2723     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2724     TRACE("(%p)->(%p)\n", This, err);
2725     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2726 }
2727
2728 static HRESULT WINAPI domdoc_setProperty(
2729     IXMLDOMDocument3* iface,
2730     BSTR p,
2731     VARIANT var)
2732 {
2733     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2734
2735     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2736
2737     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2738     {
2739         VARIANT varStr;
2740         HRESULT hr;
2741         BSTR bstr;
2742
2743         V_VT(&varStr) = VT_EMPTY;
2744         if (V_VT(&var) != VT_BSTR)
2745         {
2746             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2747                 return hr;
2748             bstr = V_BSTR(&varStr);
2749         }
2750         else
2751             bstr = V_BSTR(&var);
2752
2753         hr = S_OK;
2754         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2755             This->properties->XPath = TRUE;
2756         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2757             This->properties->XPath = FALSE;
2758         else
2759             hr = E_FAIL;
2760
2761         VariantClear(&varStr);
2762         return hr;
2763     }
2764     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2765     {
2766         VARIANT varStr;
2767         HRESULT hr;
2768         BSTR bstr;
2769         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2770         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2771         xmlXPathContextPtr ctx;
2772         struct list *pNsList;
2773         select_ns_entry* pNsEntry = NULL;
2774
2775         V_VT(&varStr) = VT_EMPTY;
2776         if (V_VT(&var) != VT_BSTR)
2777         {
2778             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2779                 return hr;
2780             bstr = V_BSTR(&varStr);
2781         }
2782         else
2783             bstr = V_BSTR(&var);
2784
2785         hr = S_OK;
2786
2787         pNsList = &(This->properties->selectNsList);
2788         clear_selectNsList(pNsList);
2789         heap_free(nsStr);
2790         nsStr = xmlchar_from_wchar(bstr);
2791
2792         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2793
2794         This->properties->selectNsStr = nsStr;
2795         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2796         if (bstr && *bstr)
2797         {
2798             ctx = xmlXPathNewContext(This->node.node->doc);
2799             pTokBegin = nsStr;
2800             for (; *pTokBegin; pTokBegin = pTokEnd)
2801             {
2802                 if (pNsEntry != NULL)
2803                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2804                 else
2805                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2806
2807                 while (*pTokBegin == ' ')
2808                     ++pTokBegin;
2809                 pTokEnd = pTokBegin;
2810                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2811                     ++pTokEnd;
2812
2813                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2814                 {
2815                     hr = E_FAIL;
2816                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2817                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2818                     continue;
2819                 }
2820
2821                 pTokBegin += 5;
2822                 if (*pTokBegin == '=')
2823                 {
2824                     /*valid for XSLPattern?*/
2825                     FIXME("Setting default xmlns not supported - skipping.\n");
2826                     continue;
2827                 }
2828                 else if (*pTokBegin == ':')
2829                 {
2830                     pNsEntry->prefix = ++pTokBegin;
2831                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2832                         ;
2833
2834                     if (pTokInner == pTokEnd)
2835                     {
2836                         hr = E_FAIL;
2837                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2838                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2839                         continue;
2840                     }
2841
2842                     pNsEntry->prefix_end = *pTokInner;
2843                     *pTokInner = 0;
2844                     ++pTokInner;
2845
2846                     if (pTokEnd-pTokInner > 1 &&
2847                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2848                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2849                     {
2850                         pNsEntry->href = ++pTokInner;
2851                         pNsEntry->href_end = *(pTokEnd-1);
2852                         *(pTokEnd-1) = 0;
2853                         list_add_tail(pNsList, &pNsEntry->entry);
2854                         /*let libxml figure out if they're valid from here ;)*/
2855                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2856                         {
2857                             hr = E_FAIL;
2858                         }
2859                         pNsEntry = NULL;
2860                         continue;
2861                     }
2862                     else
2863                     {
2864                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2865                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2866                         list_add_tail(pNsList, &pNsEntry->entry);
2867
2868                         pNsEntry = NULL;
2869                         hr = E_FAIL;
2870                         continue;
2871                     }
2872                 }
2873                 else
2874                 {
2875                     hr = E_FAIL;
2876                     continue;
2877                 }
2878             }
2879             heap_free(pNsEntry);
2880             xmlXPathFreeContext(ctx);
2881         }
2882
2883         VariantClear(&varStr);
2884         return hr;
2885     }
2886     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2887              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2888              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2889     {
2890         /* Ignore */
2891         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2892         return S_OK;
2893     }
2894
2895     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2896     return E_FAIL;
2897 }
2898
2899 static HRESULT WINAPI domdoc_getProperty(
2900     IXMLDOMDocument3* iface,
2901     BSTR p,
2902     VARIANT* var)
2903 {
2904     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2905
2906     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2907
2908     if (!var)
2909         return E_INVALIDARG;
2910
2911     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2912     {
2913         V_VT(var) = VT_BSTR;
2914         V_BSTR(var) = This->properties->XPath ?
2915                       SysAllocString(PropValueXPathW) :
2916                       SysAllocString(PropValueXSLPatternW);
2917         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2918     }
2919     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2920     {
2921         int lenA, lenW;
2922         BSTR rebuiltStr, cur;
2923         const xmlChar *nsStr;
2924         struct list *pNsList;
2925         select_ns_entry* pNsEntry;
2926
2927         V_VT(var) = VT_BSTR;
2928         nsStr = This->properties->selectNsStr;
2929         pNsList = &This->properties->selectNsList;
2930         lenA = This->properties->selectNsStr_len;
2931         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2932         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2933         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2934         cur = rebuiltStr;
2935         /* this is fine because all of the chars that end tokens are ASCII*/
2936         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2937         {
2938             while (*cur != 0) ++cur;
2939             if (pNsEntry->prefix_end)
2940             {
2941                 *cur = pNsEntry->prefix_end;
2942                 while (*cur != 0) ++cur;
2943             }
2944
2945             if (pNsEntry->href_end)
2946             {
2947                 *cur = pNsEntry->href_end;
2948             }
2949         }
2950         V_BSTR(var) = SysAllocString(rebuiltStr);
2951         heap_free(rebuiltStr);
2952         return S_OK;
2953     }
2954
2955     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2956     return E_FAIL;
2957 }
2958
2959 static HRESULT WINAPI domdoc_importNode(
2960     IXMLDOMDocument3* iface,
2961     IXMLDOMNode* node,
2962     VARIANT_BOOL deep,
2963     IXMLDOMNode** clone)
2964 {
2965     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2966     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2967     return E_NOTIMPL;
2968 }
2969
2970 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2971 {
2972     domdoc_QueryInterface,
2973     domdoc_AddRef,
2974     domdoc_Release,
2975     domdoc_GetTypeInfoCount,
2976     domdoc_GetTypeInfo,
2977     domdoc_GetIDsOfNames,
2978     domdoc_Invoke,
2979     domdoc_get_nodeName,
2980     domdoc_get_nodeValue,
2981     domdoc_put_nodeValue,
2982     domdoc_get_nodeType,
2983     domdoc_get_parentNode,
2984     domdoc_get_childNodes,
2985     domdoc_get_firstChild,
2986     domdoc_get_lastChild,
2987     domdoc_get_previousSibling,
2988     domdoc_get_nextSibling,
2989     domdoc_get_attributes,
2990     domdoc_insertBefore,
2991     domdoc_replaceChild,
2992     domdoc_removeChild,
2993     domdoc_appendChild,
2994     domdoc_hasChildNodes,
2995     domdoc_get_ownerDocument,
2996     domdoc_cloneNode,
2997     domdoc_get_nodeTypeString,
2998     domdoc_get_text,
2999     domdoc_put_text,
3000     domdoc_get_specified,
3001     domdoc_get_definition,
3002     domdoc_get_nodeTypedValue,
3003     domdoc_put_nodeTypedValue,
3004     domdoc_get_dataType,
3005     domdoc_put_dataType,
3006     domdoc_get_xml,
3007     domdoc_transformNode,
3008     domdoc_selectNodes,
3009     domdoc_selectSingleNode,
3010     domdoc_get_parsed,
3011     domdoc_get_namespaceURI,
3012     domdoc_get_prefix,
3013     domdoc_get_baseName,
3014     domdoc_transformNodeToObject,
3015     domdoc_get_doctype,
3016     domdoc_get_implementation,
3017     domdoc_get_documentElement,
3018     domdoc_put_documentElement,
3019     domdoc_createElement,
3020     domdoc_createDocumentFragment,
3021     domdoc_createTextNode,
3022     domdoc_createComment,
3023     domdoc_createCDATASection,
3024     domdoc_createProcessingInstruction,
3025     domdoc_createAttribute,
3026     domdoc_createEntityReference,
3027     domdoc_getElementsByTagName,
3028     domdoc_createNode,
3029     domdoc_nodeFromID,
3030     domdoc_load,
3031     domdoc_get_readyState,
3032     domdoc_get_parseError,
3033     domdoc_get_url,
3034     domdoc_get_async,
3035     domdoc_put_async,
3036     domdoc_abort,
3037     domdoc_loadXML,
3038     domdoc_save,
3039     domdoc_get_validateOnParse,
3040     domdoc_put_validateOnParse,
3041     domdoc_get_resolveExternals,
3042     domdoc_put_resolveExternals,
3043     domdoc_get_preserveWhiteSpace,
3044     domdoc_put_preserveWhiteSpace,
3045     domdoc_put_onreadystatechange,
3046     domdoc_put_onDataAvailable,
3047     domdoc_put_onTransformNode,
3048     domdoc_get_namespaces,
3049     domdoc_get_schemas,
3050     domdoc_putref_schemas,
3051     domdoc_validate,
3052     domdoc_setProperty,
3053     domdoc_getProperty,
3054     domdoc_validateNode,
3055     domdoc_importNode
3056 };
3057
3058 /* IConnectionPointContainer */
3059 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3060                                                               REFIID riid, void **ppv)
3061 {
3062     domdoc *This = impl_from_IConnectionPointContainer(iface);
3063     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3064 }
3065
3066 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3067 {
3068     domdoc *This = impl_from_IConnectionPointContainer(iface);
3069     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3070 }
3071
3072 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3073 {
3074     domdoc *This = impl_from_IConnectionPointContainer(iface);
3075     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3076 }
3077
3078 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3079         IEnumConnectionPoints **ppEnum)
3080 {
3081     domdoc *This = impl_from_IConnectionPointContainer(iface);
3082     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3083     return E_NOTIMPL;
3084 }
3085
3086 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3087         REFIID riid, IConnectionPoint **cp)
3088 {
3089     domdoc *This = impl_from_IConnectionPointContainer(iface);
3090     ConnectionPoint *iter;
3091
3092     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3093
3094     *cp = NULL;
3095
3096     for(iter = This->cp_list; iter; iter = iter->next)
3097     {
3098         if (IsEqualGUID(iter->iid, riid))
3099             *cp = &iter->IConnectionPoint_iface;
3100     }
3101
3102     if (*cp)
3103     {
3104         IConnectionPoint_AddRef(*cp);
3105         return S_OK;
3106     }
3107
3108     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3109     return CONNECT_E_NOCONNECTION;
3110
3111 }
3112
3113 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3114 {
3115     ConnectionPointContainer_QueryInterface,
3116     ConnectionPointContainer_AddRef,
3117     ConnectionPointContainer_Release,
3118     ConnectionPointContainer_EnumConnectionPoints,
3119     ConnectionPointContainer_FindConnectionPoint
3120 };
3121
3122 /* IConnectionPoint */
3123 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3124                                                      REFIID riid, void **ppv)
3125 {
3126     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3127
3128     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3129
3130     *ppv = NULL;
3131
3132     if (IsEqualGUID(&IID_IUnknown, riid) ||
3133         IsEqualGUID(&IID_IConnectionPoint, riid))
3134     {
3135         *ppv = iface;
3136     }
3137
3138     if (*ppv)
3139     {
3140         IConnectionPoint_AddRef(iface);
3141         return S_OK;
3142     }
3143
3144     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3145     return E_NOINTERFACE;
3146 }
3147
3148 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3149 {
3150     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3151     return IConnectionPointContainer_AddRef(This->container);
3152 }
3153
3154 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3155 {
3156     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3157     return IConnectionPointContainer_Release(This->container);
3158 }
3159
3160 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3161 {
3162     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3163
3164     TRACE("(%p)->(%p)\n", This, iid);
3165
3166     if (!iid) return E_POINTER;
3167
3168     *iid = *This->iid;
3169     return S_OK;
3170 }
3171
3172 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3173         IConnectionPointContainer **container)
3174 {
3175     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3176
3177     TRACE("(%p)->(%p)\n", This, container);
3178
3179     if (!container) return E_POINTER;
3180
3181     *container = This->container;
3182     IConnectionPointContainer_AddRef(*container);
3183     return S_OK;
3184 }
3185
3186 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3187                                              DWORD *pdwCookie)
3188 {
3189     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3190     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3191     return E_NOTIMPL;
3192 }
3193
3194 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3195 {
3196     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3197
3198     TRACE("(%p)->(%d)\n", This, cookie);
3199
3200     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3201         return CONNECT_E_NOCONNECTION;
3202
3203     IUnknown_Release(This->sinks[cookie-1].unk);
3204     This->sinks[cookie-1].unk = NULL;
3205
3206     return S_OK;
3207 }
3208
3209 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3210                                                       IEnumConnections **ppEnum)
3211 {
3212     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3213     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3214     return E_NOTIMPL;
3215 }
3216
3217 static const IConnectionPointVtbl ConnectionPointVtbl =
3218 {
3219     ConnectionPoint_QueryInterface,
3220     ConnectionPoint_AddRef,
3221     ConnectionPoint_Release,
3222     ConnectionPoint_GetConnectionInterface,
3223     ConnectionPoint_GetConnectionPointContainer,
3224     ConnectionPoint_Advise,
3225     ConnectionPoint_Unadvise,
3226     ConnectionPoint_EnumConnections
3227 };
3228
3229 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3230 {
3231     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3232     cp->doc = doc;
3233     cp->iid = riid;
3234     cp->sinks = NULL;
3235     cp->sinks_size = 0;
3236
3237     cp->next = doc->cp_list;
3238     doc->cp_list = cp;
3239
3240     cp->container = &doc->IConnectionPointContainer_iface;
3241 }
3242
3243 /* domdoc implementation of IObjectWithSite */
3244 static HRESULT WINAPI
3245 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3246 {
3247     domdoc *This = impl_from_IObjectWithSite(iface);
3248     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3249 }
3250
3251 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3252 {
3253     domdoc *This = impl_from_IObjectWithSite(iface);
3254     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3255 }
3256
3257 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3258 {
3259     domdoc *This = impl_from_IObjectWithSite(iface);
3260     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3261 }
3262
3263 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3264 {
3265     domdoc *This = impl_from_IObjectWithSite(iface);
3266
3267     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3268
3269     if ( !This->site )
3270         return E_FAIL;
3271
3272     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3273 }
3274
3275 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3276 {
3277     domdoc *This = impl_from_IObjectWithSite(iface);
3278
3279     TRACE("(%p)->(%p)\n", iface, punk);
3280
3281     if(!punk)
3282     {
3283         if(This->site)
3284         {
3285             IUnknown_Release( This->site );
3286             This->site = NULL;
3287         }
3288
3289         return S_OK;
3290     }
3291
3292     IUnknown_AddRef( punk );
3293
3294     if(This->site)
3295         IUnknown_Release( This->site );
3296
3297     This->site = punk;
3298
3299     return S_OK;
3300 }
3301
3302 static const IObjectWithSiteVtbl domdocObjectSite =
3303 {
3304     domdoc_ObjectWithSite_QueryInterface,
3305     domdoc_ObjectWithSite_AddRef,
3306     domdoc_ObjectWithSite_Release,
3307     domdoc_ObjectWithSite_SetSite,
3308     domdoc_ObjectWithSite_GetSite
3309 };
3310
3311 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3312 {
3313     domdoc *This = impl_from_IObjectSafety(iface);
3314     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3315 }
3316
3317 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3318 {
3319     domdoc *This = impl_from_IObjectSafety(iface);
3320     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3321 }
3322
3323 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3324 {
3325     domdoc *This = impl_from_IObjectSafety(iface);
3326     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3327 }
3328
3329 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3330
3331 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3332         DWORD *supported, DWORD *enabled)
3333 {
3334     domdoc *This = impl_from_IObjectSafety(iface);
3335
3336     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3337
3338     if(!supported || !enabled) return E_POINTER;
3339
3340     *supported = SAFETY_SUPPORTED_OPTIONS;
3341     *enabled = This->safeopt;
3342
3343     return S_OK;
3344 }
3345
3346 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3347         DWORD mask, DWORD enabled)
3348 {
3349     domdoc *This = impl_from_IObjectSafety(iface);
3350     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3351
3352     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3353         return E_FAIL;
3354
3355     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3356
3357     return S_OK;
3358 }
3359
3360 #undef SAFETY_SUPPORTED_OPTIONS
3361
3362 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3363     domdoc_Safety_QueryInterface,
3364     domdoc_Safety_AddRef,
3365     domdoc_Safety_Release,
3366     domdoc_Safety_GetInterfaceSafetyOptions,
3367     domdoc_Safety_SetInterfaceSafetyOptions
3368 };
3369
3370 static const tid_t domdoc_iface_tids[] = {
3371     IXMLDOMDocument3_tid,
3372     0
3373 };
3374
3375 static dispex_static_data_t domdoc_dispex = {
3376     NULL,
3377     IXMLDOMDocument3_tid,
3378     NULL,
3379     domdoc_iface_tids
3380 };
3381
3382 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3383 {
3384     domdoc *doc;
3385
3386     doc = heap_alloc( sizeof (*doc) );
3387     if( !doc )
3388         return E_OUTOFMEMORY;
3389
3390     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3391     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3392     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3393     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3394     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3395     doc->ref = 1;
3396     doc->async = VARIANT_TRUE;
3397     doc->validating = 0;
3398     doc->resolving = 0;
3399     doc->properties = properties_from_xmlDocPtr(xmldoc);
3400     doc->error = S_OK;
3401     doc->stream = NULL;
3402     doc->site = NULL;
3403     doc->safeopt = 0;
3404     doc->bsc = NULL;
3405     doc->cp_list = NULL;
3406     memset(doc->events, 0, sizeof(doc->events));
3407
3408     /* events connection points */
3409     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3410     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3411     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3412
3413     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3414             &domdoc_dispex);
3415
3416     *document = &doc->IXMLDOMDocument3_iface;
3417
3418     TRACE("returning iface %p\n", *document);
3419     return S_OK;
3420 }
3421
3422 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3423 {
3424     xmlDocPtr xmldoc;
3425     HRESULT hr;
3426
3427     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3428
3429     xmldoc = xmlNewDoc(NULL);
3430     if(!xmldoc)
3431         return E_OUTOFMEMORY;
3432
3433     xmldoc->_private = create_priv();
3434     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3435
3436     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3437     if(FAILED(hr))
3438     {
3439         free_properties(properties_from_xmlDocPtr(xmldoc));
3440         heap_free(xmldoc->_private);
3441         xmlFreeDoc(xmldoc);
3442         return hr;
3443     }
3444
3445     return hr;
3446 }
3447
3448 IUnknown* create_domdoc( xmlNodePtr document )
3449 {
3450     void* pObj = NULL;
3451     HRESULT hr;
3452
3453     TRACE("(%p)\n", document);
3454
3455     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3456     if (FAILED(hr))
3457         return NULL;
3458
3459     return pObj;
3460 }
3461
3462 #else
3463
3464 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3465 {
3466     MESSAGE("This program tried to use a DOMDocument object, but\n"
3467             "libxml2 support was not present at compile time.\n");
3468     return E_NOTIMPL;
3469 }
3470
3471 #endif