msi: Execute custom actions in the right script.
[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 {
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 static HRESULT WINAPI domdoc_get_namespaceURI(
1373     IXMLDOMDocument3 *iface,
1374     BSTR* namespaceURI )
1375 {
1376     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1377     TRACE("(%p)->(%p)\n", This, namespaceURI);
1378     return return_null_bstr( namespaceURI );
1379 }
1380
1381 static HRESULT WINAPI domdoc_get_prefix(
1382     IXMLDOMDocument3 *iface,
1383     BSTR* prefix )
1384 {
1385     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1386     TRACE("(%p)->(%p)\n", This, prefix);
1387     return return_null_bstr( prefix );
1388 }
1389
1390
1391 static HRESULT WINAPI domdoc_get_baseName(
1392     IXMLDOMDocument3 *iface,
1393     BSTR* name )
1394 {
1395     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1396     TRACE("(%p)->(%p)\n", This, name);
1397     return return_null_bstr( name );
1398 }
1399
1400
1401 static HRESULT WINAPI domdoc_transformNodeToObject(
1402     IXMLDOMDocument3 *iface,
1403     IXMLDOMNode* stylesheet,
1404     VARIANT outputObject)
1405 {
1406     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1407     FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1408     return E_NOTIMPL;
1409 }
1410
1411
1412 static HRESULT WINAPI domdoc_get_doctype(
1413     IXMLDOMDocument3 *iface,
1414     IXMLDOMDocumentType** doctype )
1415 {
1416     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1417     IXMLDOMNode *node;
1418     xmlDtdPtr dtd;
1419     HRESULT hr;
1420
1421     TRACE("(%p)->(%p)\n", This, doctype);
1422
1423     if (!doctype) return E_INVALIDARG;
1424
1425     *doctype = NULL;
1426
1427     dtd = xmlGetIntSubset(get_doc(This));
1428     if (!dtd) return S_FALSE;
1429
1430     node = create_node((xmlNodePtr)dtd);
1431     if (!node) return S_FALSE;
1432
1433     hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1434     IXMLDOMNode_Release(node);
1435
1436     return hr;
1437 }
1438
1439
1440 static HRESULT WINAPI domdoc_get_implementation(
1441     IXMLDOMDocument3 *iface,
1442     IXMLDOMImplementation** impl )
1443 {
1444     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1445
1446     TRACE("(%p)->(%p)\n", This, impl);
1447
1448     if(!impl)
1449         return E_INVALIDARG;
1450
1451     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1452
1453     return S_OK;
1454 }
1455
1456 static HRESULT WINAPI domdoc_get_documentElement(
1457     IXMLDOMDocument3 *iface,
1458     IXMLDOMElement** DOMElement )
1459 {
1460     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1461     IXMLDOMNode *element_node;
1462     xmlNodePtr root;
1463     HRESULT hr;
1464
1465     TRACE("(%p)->(%p)\n", This, DOMElement);
1466
1467     if(!DOMElement)
1468         return E_INVALIDARG;
1469
1470     *DOMElement = NULL;
1471
1472     root = xmlDocGetRootElement( get_doc(This) );
1473     if ( !root )
1474         return S_FALSE;
1475
1476     element_node = create_node( root );
1477     if(!element_node) return S_FALSE;
1478
1479     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1480     IXMLDOMNode_Release(element_node);
1481
1482     return hr;
1483 }
1484
1485
1486 static HRESULT WINAPI domdoc_put_documentElement(
1487     IXMLDOMDocument3 *iface,
1488     IXMLDOMElement* DOMElement )
1489 {
1490     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1491     IXMLDOMNode *elementNode;
1492     xmlNodePtr oldRoot;
1493     xmlnode *xmlNode;
1494     HRESULT hr;
1495
1496     TRACE("(%p)->(%p)\n", This, DOMElement);
1497
1498     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1499     if(FAILED(hr))
1500         return hr;
1501
1502     xmlNode = get_node_obj( elementNode );
1503     if(!xmlNode) return E_FAIL;
1504
1505     if(!xmlNode->node->parent)
1506         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1507             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1508
1509     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1510     IXMLDOMNode_Release( elementNode );
1511
1512     if(oldRoot)
1513         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1514
1515     return S_OK;
1516 }
1517
1518
1519 static HRESULT WINAPI domdoc_createElement(
1520     IXMLDOMDocument3 *iface,
1521     BSTR tagname,
1522     IXMLDOMElement** element )
1523 {
1524     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1525     IXMLDOMNode *node;
1526     VARIANT type;
1527     HRESULT hr;
1528
1529     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1530
1531     if (!element || !tagname) return E_INVALIDARG;
1532
1533     V_VT(&type) = VT_I1;
1534     V_I1(&type) = NODE_ELEMENT;
1535
1536     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1537     if (hr == S_OK)
1538     {
1539         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1540         IXMLDOMNode_Release(node);
1541     }
1542
1543     return hr;
1544 }
1545
1546
1547 static HRESULT WINAPI domdoc_createDocumentFragment(
1548     IXMLDOMDocument3 *iface,
1549     IXMLDOMDocumentFragment** frag )
1550 {
1551     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1552     IXMLDOMNode *node;
1553     VARIANT type;
1554     HRESULT hr;
1555
1556     TRACE("(%p)->(%p)\n", This, frag);
1557
1558     if (!frag) return E_INVALIDARG;
1559
1560     *frag = NULL;
1561
1562     V_VT(&type) = VT_I1;
1563     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1564
1565     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1566     if (hr == S_OK)
1567     {
1568         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1569         IXMLDOMNode_Release(node);
1570     }
1571
1572     return hr;
1573 }
1574
1575
1576 static HRESULT WINAPI domdoc_createTextNode(
1577     IXMLDOMDocument3 *iface,
1578     BSTR data,
1579     IXMLDOMText** text )
1580 {
1581     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1582     IXMLDOMNode *node;
1583     VARIANT type;
1584     HRESULT hr;
1585
1586     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1587
1588     if (!text) return E_INVALIDARG;
1589
1590     *text = NULL;
1591
1592     V_VT(&type) = VT_I1;
1593     V_I1(&type) = NODE_TEXT;
1594
1595     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1596     if (hr == S_OK)
1597     {
1598         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1599         IXMLDOMNode_Release(node);
1600         hr = IXMLDOMText_put_data(*text, data);
1601     }
1602
1603     return hr;
1604 }
1605
1606
1607 static HRESULT WINAPI domdoc_createComment(
1608     IXMLDOMDocument3 *iface,
1609     BSTR data,
1610     IXMLDOMComment** comment )
1611 {
1612     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1613     VARIANT type;
1614     HRESULT hr;
1615     IXMLDOMNode *node;
1616
1617     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1618
1619     if (!comment) return E_INVALIDARG;
1620
1621     *comment = NULL;
1622
1623     V_VT(&type) = VT_I1;
1624     V_I1(&type) = NODE_COMMENT;
1625
1626     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1627     if (hr == S_OK)
1628     {
1629         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1630         IXMLDOMNode_Release(node);
1631         hr = IXMLDOMComment_put_data(*comment, data);
1632     }
1633
1634     return hr;
1635 }
1636
1637
1638 static HRESULT WINAPI domdoc_createCDATASection(
1639     IXMLDOMDocument3 *iface,
1640     BSTR data,
1641     IXMLDOMCDATASection** cdata )
1642 {
1643     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1644     IXMLDOMNode *node;
1645     VARIANT type;
1646     HRESULT hr;
1647
1648     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1649
1650     if (!cdata) return E_INVALIDARG;
1651
1652     *cdata = NULL;
1653
1654     V_VT(&type) = VT_I1;
1655     V_I1(&type) = NODE_CDATA_SECTION;
1656
1657     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1658     if (hr == S_OK)
1659     {
1660         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1661         IXMLDOMNode_Release(node);
1662         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1663     }
1664
1665     return hr;
1666 }
1667
1668
1669 static HRESULT WINAPI domdoc_createProcessingInstruction(
1670     IXMLDOMDocument3 *iface,
1671     BSTR target,
1672     BSTR data,
1673     IXMLDOMProcessingInstruction** pi )
1674 {
1675     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1676     IXMLDOMNode *node;
1677     VARIANT type;
1678     HRESULT hr;
1679
1680     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1681
1682     if (!pi) return E_INVALIDARG;
1683
1684     *pi = NULL;
1685
1686     V_VT(&type) = VT_I1;
1687     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1688
1689     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1690     if (hr == S_OK)
1691     {
1692         xmlnode *node_obj;
1693
1694         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1695         node_obj = get_node_obj(node);
1696         hr = node_set_content(node_obj, data);
1697
1698         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1699         IXMLDOMNode_Release(node);
1700     }
1701
1702     return hr;
1703 }
1704
1705
1706 static HRESULT WINAPI domdoc_createAttribute(
1707     IXMLDOMDocument3 *iface,
1708     BSTR name,
1709     IXMLDOMAttribute** attribute )
1710 {
1711     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1712     IXMLDOMNode *node;
1713     VARIANT type;
1714     HRESULT hr;
1715
1716     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1717
1718     if (!attribute || !name) return E_INVALIDARG;
1719
1720     V_VT(&type) = VT_I1;
1721     V_I1(&type) = NODE_ATTRIBUTE;
1722
1723     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1724     if (hr == S_OK)
1725     {
1726         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1727         IXMLDOMNode_Release(node);
1728     }
1729
1730     return hr;
1731 }
1732
1733
1734 static HRESULT WINAPI domdoc_createEntityReference(
1735     IXMLDOMDocument3 *iface,
1736     BSTR name,
1737     IXMLDOMEntityReference** entityref )
1738 {
1739     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1740     IXMLDOMNode *node;
1741     VARIANT type;
1742     HRESULT hr;
1743
1744     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1745
1746     if (!entityref) return E_INVALIDARG;
1747
1748     *entityref = NULL;
1749
1750     V_VT(&type) = VT_I1;
1751     V_I1(&type) = NODE_ENTITY_REFERENCE;
1752
1753     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1754     if (hr == S_OK)
1755     {
1756         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1757         IXMLDOMNode_Release(node);
1758     }
1759
1760     return hr;
1761 }
1762
1763 xmlChar* tagName_to_XPath(const BSTR tagName)
1764 {
1765     xmlChar *query, *tmp;
1766     static const xmlChar mod_pre[] = "*[local-name()='";
1767     static const xmlChar mod_post[] = "']";
1768     static const xmlChar prefix[] = "descendant::";
1769     const WCHAR *tokBegin, *tokEnd;
1770     int len;
1771
1772     query = xmlStrdup(prefix);
1773
1774     tokBegin = tagName;
1775     while (tokBegin && *tokBegin)
1776     {
1777         switch (*tokBegin)
1778         {
1779         case '/':
1780             query = xmlStrcat(query, BAD_CAST "/");
1781             ++tokBegin;
1782             break;
1783         case '*':
1784             query = xmlStrcat(query, BAD_CAST "*");
1785             ++tokBegin;
1786             break;
1787         default:
1788             query = xmlStrcat(query, mod_pre);
1789             tokEnd = tokBegin;
1790             while (*tokEnd && *tokEnd != '/')
1791                 ++tokEnd;
1792             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1793             tmp = xmlMalloc(len);
1794             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1795             query = xmlStrncat(query, tmp, len);
1796             xmlFree(tmp);
1797             tokBegin = tokEnd;
1798             query = xmlStrcat(query, mod_post);
1799         }
1800     }
1801
1802     return query;
1803 }
1804
1805 static HRESULT WINAPI domdoc_getElementsByTagName(
1806     IXMLDOMDocument3 *iface,
1807     BSTR tagName,
1808     IXMLDOMNodeList** resultList )
1809 {
1810     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1811     xmlChar *query;
1812     HRESULT hr;
1813     BOOL XPath;
1814
1815     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1816
1817     if (!tagName || !resultList) return E_INVALIDARG;
1818
1819     XPath = This->properties->XPath;
1820     This->properties->XPath = TRUE;
1821     query = tagName_to_XPath(tagName);
1822     hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1823     xmlFree(query);
1824     This->properties->XPath = XPath;
1825
1826     return hr;
1827 }
1828
1829 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1830 {
1831     VARIANT tmp;
1832     HRESULT hr;
1833
1834     VariantInit(&tmp);
1835     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1836     if(FAILED(hr))
1837         return E_INVALIDARG;
1838
1839     *type = V_I4(&tmp);
1840
1841     return S_OK;
1842 }
1843
1844 static HRESULT WINAPI domdoc_createNode(
1845     IXMLDOMDocument3 *iface,
1846     VARIANT Type,
1847     BSTR name,
1848     BSTR namespaceURI,
1849     IXMLDOMNode** node )
1850 {
1851     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1852     DOMNodeType node_type;
1853     xmlNodePtr xmlnode;
1854     xmlChar *xml_name, *href;
1855     HRESULT hr;
1856
1857     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1858
1859     if(!node) return E_INVALIDARG;
1860
1861     hr = get_node_type(Type, &node_type);
1862     if(FAILED(hr)) return hr;
1863
1864     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1865         FIXME("nodes with namespaces currently not supported.\n");
1866
1867     TRACE("node_type %d\n", node_type);
1868
1869     /* exit earlier for types that need name */
1870     switch(node_type)
1871     {
1872     case NODE_ELEMENT:
1873     case NODE_ATTRIBUTE:
1874     case NODE_ENTITY_REFERENCE:
1875     case NODE_PROCESSING_INSTRUCTION:
1876         if (!name || *name == 0) return E_FAIL;
1877         break;
1878     default:
1879         break;
1880     }
1881
1882     xml_name = xmlchar_from_wchar(name);
1883     /* prevent empty href to be allocated */
1884     href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1885
1886     switch(node_type)
1887     {
1888     case NODE_ELEMENT:
1889     {
1890         xmlChar *local, *prefix;
1891
1892         local = xmlSplitQName2(xml_name, &prefix);
1893
1894         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1895
1896         /* allow to create default namespace xmlns= */
1897         if (local || (href && *href))
1898         {
1899             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1900             xmlSetNs(xmlnode, ns);
1901         }
1902
1903         xmlFree(local);
1904         xmlFree(prefix);
1905
1906         break;
1907     }
1908     case NODE_ATTRIBUTE:
1909         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1910         break;
1911     case NODE_TEXT:
1912         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1913         break;
1914     case NODE_CDATA_SECTION:
1915         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1916         break;
1917     case NODE_ENTITY_REFERENCE:
1918         xmlnode = xmlNewReference(get_doc(This), xml_name);
1919         break;
1920     case NODE_PROCESSING_INSTRUCTION:
1921 #ifdef HAVE_XMLNEWDOCPI
1922         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1923 #else
1924         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1925         xmlnode = NULL;
1926 #endif
1927         break;
1928     case NODE_COMMENT:
1929         xmlnode = xmlNewDocComment(get_doc(This), NULL);
1930         break;
1931     case NODE_DOCUMENT_FRAGMENT:
1932         xmlnode = xmlNewDocFragment(get_doc(This));
1933         break;
1934     /* unsupported types */
1935     case NODE_DOCUMENT:
1936     case NODE_DOCUMENT_TYPE:
1937     case NODE_ENTITY:
1938     case NODE_NOTATION:
1939         heap_free(xml_name);
1940         return E_INVALIDARG;
1941     default:
1942         FIXME("unhandled node type %d\n", node_type);
1943         xmlnode = NULL;
1944         break;
1945     }
1946
1947     *node = create_node(xmlnode);
1948     heap_free(xml_name);
1949     heap_free(href);
1950
1951     if(*node)
1952     {
1953         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1954         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1955         return S_OK;
1956     }
1957
1958     return E_FAIL;
1959 }
1960
1961 static HRESULT WINAPI domdoc_nodeFromID(
1962     IXMLDOMDocument3 *iface,
1963     BSTR idString,
1964     IXMLDOMNode** node )
1965 {
1966     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1967     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1968     return E_NOTIMPL;
1969 }
1970
1971 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1972 {
1973     domdoc *This = obj;
1974     xmlDocPtr xmldoc;
1975
1976     xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1977     if(xmldoc) {
1978         xmldoc->_private = create_priv();
1979         return attach_xmldoc(This, xmldoc);
1980     }
1981
1982     return S_OK;
1983 }
1984
1985 static HRESULT doread( domdoc *This, LPWSTR filename )
1986 {
1987     bsc_t *bsc;
1988     HRESULT hr;
1989
1990     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1991     if(FAILED(hr))
1992         return hr;
1993
1994     if(This->bsc) {
1995         hr = detach_bsc(This->bsc);
1996         if(FAILED(hr))
1997             return hr;
1998     }
1999
2000     This->bsc = bsc;
2001     return S_OK;
2002 }
2003
2004 static HRESULT WINAPI domdoc_load(
2005     IXMLDOMDocument3 *iface,
2006     VARIANT source,
2007     VARIANT_BOOL* isSuccessful )
2008 {
2009     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2010     LPWSTR filename = NULL;
2011     HRESULT hr = S_FALSE;
2012     IXMLDOMDocument3 *pNewDoc = NULL;
2013     IStream *pStream = NULL;
2014     xmlDocPtr xmldoc;
2015
2016     TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2017
2018     if (!isSuccessful)
2019         return E_POINTER;
2020     *isSuccessful = VARIANT_FALSE;
2021
2022     assert( &This->node );
2023
2024     switch( V_VT(&source) )
2025     {
2026     case VT_BSTR:
2027         filename = V_BSTR(&source);
2028         break;
2029     case VT_BSTR|VT_BYREF:
2030         if (!V_BSTRREF(&source)) return E_INVALIDARG;
2031         filename = *V_BSTRREF(&source);
2032         break;
2033     case VT_ARRAY|VT_UI1:
2034         {
2035             SAFEARRAY *psa = V_ARRAY(&source);
2036             char *str;
2037             LONG len;
2038             UINT dim = SafeArrayGetDim(psa);
2039
2040             switch (dim)
2041             {
2042             case 0:
2043                 ERR("SAFEARRAY == NULL\n");
2044                 hr = This->error = E_INVALIDARG;
2045                 break;
2046             case 1:
2047                 /* Only takes UTF-8 strings.
2048                  * NOT NULL-terminated. */
2049                 SafeArrayAccessData(psa, (void**)&str);
2050                 SafeArrayGetUBound(psa, 1, &len);
2051
2052                 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2053                 {
2054                     hr = This->error = S_OK;
2055                     *isSuccessful = VARIANT_TRUE;
2056                     TRACE("parsed document %p\n", xmldoc);
2057                 }
2058                 else
2059                 {
2060                     This->error = E_FAIL;
2061                     TRACE("failed to parse document\n");
2062                 }
2063
2064                 SafeArrayUnaccessData(psa);
2065
2066                 if(xmldoc)
2067                 {
2068                     xmldoc->_private = create_priv();
2069                     return attach_xmldoc(This, xmldoc);
2070                 }
2071                 break;
2072             default:
2073                 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2074                 hr = This->error = E_NOTIMPL;
2075             }
2076         }
2077         break;
2078     case VT_UNKNOWN:
2079         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2080         if(hr == S_OK)
2081         {
2082             if(pNewDoc)
2083             {
2084                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2085                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2086                 hr = attach_xmldoc(This, xmldoc);
2087
2088                 if(SUCCEEDED(hr))
2089                     *isSuccessful = VARIANT_TRUE;
2090
2091                 return hr;
2092             }
2093         }
2094         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2095         if(hr == S_OK)
2096         {
2097             IPersistStream *pDocStream;
2098             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2099             if(hr == S_OK)
2100             {
2101                 hr = IPersistStream_Load(pDocStream, pStream);
2102                 IStream_Release(pStream);
2103                 if(hr == S_OK)
2104                 {
2105                     *isSuccessful = VARIANT_TRUE;
2106
2107                     TRACE("Using IStream to load Document\n");
2108                     return S_OK;
2109                 }
2110                 else
2111                 {
2112                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2113                 }
2114             }
2115             else
2116             {
2117                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2118             }
2119         }
2120         else
2121         {
2122             /* ISequentialStream */
2123             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2124         }
2125         break;
2126      default:
2127             FIXME("VT type not supported (%d)\n", V_VT(&source));
2128     }
2129
2130     if ( filename )
2131     {
2132         hr = doread( This, filename );
2133
2134         if ( FAILED(hr) )
2135             This->error = E_FAIL;
2136         else
2137         {
2138             hr = This->error = S_OK;
2139             *isSuccessful = VARIANT_TRUE;
2140         }
2141     }
2142
2143     if(!filename || FAILED(hr)) {
2144         xmldoc = xmlNewDoc(NULL);
2145         xmldoc->_private = create_priv();
2146         hr = attach_xmldoc(This, xmldoc);
2147         if(SUCCEEDED(hr))
2148             hr = S_FALSE;
2149     }
2150
2151     TRACE("ret (%d)\n", hr);
2152
2153     return hr;
2154 }
2155
2156
2157 static HRESULT WINAPI domdoc_get_readyState(
2158     IXMLDOMDocument3 *iface,
2159     LONG *value )
2160 {
2161     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2162     FIXME("stub! (%p)->(%p)\n", This, value);
2163
2164     if (!value)
2165         return E_INVALIDARG;
2166
2167     *value = READYSTATE_COMPLETE;
2168     return S_OK;
2169 }
2170
2171
2172 static HRESULT WINAPI domdoc_get_parseError(
2173     IXMLDOMDocument3 *iface,
2174     IXMLDOMParseError** errorObj )
2175 {
2176     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2177     static const WCHAR err[] = {'e','r','r','o','r',0};
2178     BSTR error_string = NULL;
2179
2180     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2181
2182     if(This->error)
2183         error_string = SysAllocString(err);
2184
2185     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2186     if(!*errorObj) return E_OUTOFMEMORY;
2187     return S_OK;
2188 }
2189
2190
2191 static HRESULT WINAPI domdoc_get_url(
2192     IXMLDOMDocument3 *iface,
2193     BSTR* urlString )
2194 {
2195     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2196     FIXME("(%p)->(%p)\n", This, urlString);
2197     return E_NOTIMPL;
2198 }
2199
2200
2201 static HRESULT WINAPI domdoc_get_async(
2202     IXMLDOMDocument3 *iface,
2203     VARIANT_BOOL* isAsync )
2204 {
2205     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2206
2207     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2208     *isAsync = This->async;
2209     return S_OK;
2210 }
2211
2212
2213 static HRESULT WINAPI domdoc_put_async(
2214     IXMLDOMDocument3 *iface,
2215     VARIANT_BOOL isAsync )
2216 {
2217     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2218
2219     TRACE("(%p)->(%d)\n", This, isAsync);
2220     This->async = isAsync;
2221     return S_OK;
2222 }
2223
2224
2225 static HRESULT WINAPI domdoc_abort(
2226     IXMLDOMDocument3 *iface )
2227 {
2228     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2229     FIXME("%p\n", This);
2230     return E_NOTIMPL;
2231 }
2232
2233 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2234 static HRESULT WINAPI domdoc_loadXML(
2235     IXMLDOMDocument3 *iface,
2236     BSTR data,
2237     VARIANT_BOOL* isSuccessful )
2238 {
2239     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2240     xmlDocPtr xmldoc = NULL;
2241     HRESULT hr = S_FALSE, hr2;
2242
2243     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2244
2245     assert ( &This->node );
2246
2247     if ( isSuccessful )
2248     {
2249         *isSuccessful = VARIANT_FALSE;
2250
2251         if (data)
2252         {
2253             WCHAR *ptr = data;
2254
2255             /* skip leading spaces if needed */
2256             if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2257                  while (*ptr)
2258                     if (isspaceW(*ptr)) ptr++; else break;
2259
2260             xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2261             if ( !xmldoc )
2262             {
2263                 This->error = E_FAIL;
2264                 TRACE("failed to parse document\n");
2265             }
2266             else
2267             {
2268                 hr = This->error = S_OK;
2269                 *isSuccessful = VARIANT_TRUE;
2270                 TRACE("parsed document %p\n", xmldoc);
2271             }
2272         }
2273     }
2274     if(!xmldoc)
2275         xmldoc = xmlNewDoc(NULL);
2276
2277     xmldoc->_private = create_priv();
2278
2279     hr2 = attach_xmldoc(This, xmldoc);
2280     if( FAILED(hr2) )
2281         hr = hr2;
2282
2283     return hr;
2284 }
2285
2286 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2287 {
2288     DWORD written = -1;
2289
2290     if(!WriteFile(ctx, buffer, len, &written, NULL))
2291     {
2292         WARN("write error\n");
2293         return -1;
2294     }
2295     else
2296         return written;
2297 }
2298
2299 static int XMLCALL domdoc_save_closecallback(void *ctx)
2300 {
2301     return CloseHandle(ctx) ? 0 : -1;
2302 }
2303
2304 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2305 {
2306     ULONG written = 0;
2307     HRESULT hr;
2308
2309     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2310     if (hr != S_OK)
2311     {
2312         WARN("stream write error: 0x%08x\n", hr);
2313         return -1;
2314     }
2315     else
2316         return written;
2317 }
2318
2319 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2320 {
2321     IStream_Release((IStream*)ctx);
2322     return 0;
2323 }
2324
2325 static HRESULT WINAPI domdoc_save(
2326     IXMLDOMDocument3 *iface,
2327     VARIANT destination )
2328 {
2329     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2330     xmlSaveCtxtPtr ctx = NULL;
2331     xmlNodePtr xmldecl;
2332     HRESULT ret = S_OK;
2333
2334     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2335
2336     switch (V_VT(&destination))
2337     {
2338     case VT_UNKNOWN:
2339         {
2340             IUnknown *pUnk = V_UNKNOWN(&destination);
2341             IXMLDOMDocument3 *document;
2342             IStream *stream;
2343
2344             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2345             if(ret == S_OK)
2346             {
2347                 VARIANT_BOOL success;
2348                 BSTR xml;
2349
2350                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2351                 if(ret == S_OK)
2352                 {
2353                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2354                     SysFreeString(xml);
2355                 }
2356
2357                 IXMLDOMDocument3_Release(document);
2358                 return ret;
2359             }
2360
2361             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2362             if(ret == S_OK)
2363             {
2364                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2365                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2366
2367                 if(!ctx)
2368                 {
2369                     IStream_Release(stream);
2370                     return E_FAIL;
2371                 }
2372             }
2373         }
2374         break;
2375
2376     case VT_BSTR:
2377     case VT_BSTR | VT_BYREF:
2378         {
2379             /* save with file path */
2380             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2381                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2382             if( handle == INVALID_HANDLE_VALUE )
2383             {
2384                 WARN("failed to create file\n");
2385                 return E_FAIL;
2386             }
2387
2388             /* disable top XML declaration */
2389             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2390                               handle, NULL, XML_SAVE_NO_DECL);
2391             if (!ctx)
2392             {
2393                 CloseHandle(handle);
2394                 return E_FAIL;
2395             }
2396         }
2397         break;
2398
2399     default:
2400         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2401         return S_FALSE;
2402     }
2403
2404     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2405     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2406     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2407
2408     /* will release resources through close callback */
2409     xmlSaveClose(ctx);
2410
2411     return ret;
2412 }
2413
2414 static HRESULT WINAPI domdoc_get_validateOnParse(
2415     IXMLDOMDocument3 *iface,
2416     VARIANT_BOOL* isValidating )
2417 {
2418     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2419     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2420     *isValidating = This->validating;
2421     return S_OK;
2422 }
2423
2424
2425 static HRESULT WINAPI domdoc_put_validateOnParse(
2426     IXMLDOMDocument3 *iface,
2427     VARIANT_BOOL isValidating )
2428 {
2429     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2430     TRACE("(%p)->(%d)\n", This, isValidating);
2431     This->validating = isValidating;
2432     return S_OK;
2433 }
2434
2435
2436 static HRESULT WINAPI domdoc_get_resolveExternals(
2437     IXMLDOMDocument3 *iface,
2438     VARIANT_BOOL* isResolving )
2439 {
2440     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2441     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2442     *isResolving = This->resolving;
2443     return S_OK;
2444 }
2445
2446
2447 static HRESULT WINAPI domdoc_put_resolveExternals(
2448     IXMLDOMDocument3 *iface,
2449     VARIANT_BOOL isResolving )
2450 {
2451     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2452     TRACE("(%p)->(%d)\n", This, isResolving);
2453     This->resolving = isResolving;
2454     return S_OK;
2455 }
2456
2457
2458 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2459     IXMLDOMDocument3 *iface,
2460     VARIANT_BOOL* isPreserving )
2461 {
2462     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2463     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2464     *isPreserving = This->properties->preserving;
2465     return S_OK;
2466 }
2467
2468
2469 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2470     IXMLDOMDocument3 *iface,
2471     VARIANT_BOOL isPreserving )
2472 {
2473     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2474     TRACE("(%p)->(%d)\n", This, isPreserving);
2475     This->properties->preserving = isPreserving;
2476     return S_OK;
2477 }
2478
2479
2480 static HRESULT WINAPI domdoc_put_onreadystatechange(
2481     IXMLDOMDocument3 *iface,
2482     VARIANT event )
2483 {
2484     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2485
2486     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2487     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2488 }
2489
2490
2491 static HRESULT WINAPI domdoc_put_onDataAvailable(
2492     IXMLDOMDocument3 *iface,
2493     VARIANT onDataAvailableSink )
2494 {
2495     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496     FIXME("%p\n", This);
2497     return E_NOTIMPL;
2498 }
2499
2500 static HRESULT WINAPI domdoc_put_onTransformNode(
2501     IXMLDOMDocument3 *iface,
2502     VARIANT onTransformNodeSink )
2503 {
2504     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505     FIXME("%p\n", This);
2506     return E_NOTIMPL;
2507 }
2508
2509 static HRESULT WINAPI domdoc_get_namespaces(
2510     IXMLDOMDocument3* iface,
2511     IXMLDOMSchemaCollection** schemaCollection )
2512 {
2513     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514     FIXME("(%p)->(%p)\n", This, schemaCollection);
2515     return E_NOTIMPL;
2516 }
2517
2518 static HRESULT WINAPI domdoc_get_schemas(
2519     IXMLDOMDocument3* iface,
2520     VARIANT* var1 )
2521 {
2522     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523     HRESULT hr = S_FALSE;
2524     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2525
2526     TRACE("(%p)->(%p)\n", This, var1);
2527
2528     VariantInit(var1); /* Test shows we don't call VariantClear here */
2529     V_VT(var1) = VT_NULL;
2530
2531     if(cur_schema)
2532     {
2533         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2534         if(SUCCEEDED(hr))
2535             V_VT(var1) = VT_DISPATCH;
2536     }
2537     return hr;
2538 }
2539
2540 static HRESULT WINAPI domdoc_putref_schemas(
2541     IXMLDOMDocument3* iface,
2542     VARIANT var1)
2543 {
2544     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2545     HRESULT hr = E_FAIL;
2546     IXMLDOMSchemaCollection2* new_schema = NULL;
2547
2548     FIXME("(%p): semi-stub\n", This);
2549     switch(V_VT(&var1))
2550     {
2551     case VT_UNKNOWN:
2552         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2553         break;
2554
2555     case VT_DISPATCH:
2556         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2557         break;
2558
2559     case VT_NULL:
2560     case VT_EMPTY:
2561         hr = S_OK;
2562         break;
2563
2564     default:
2565         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2566     }
2567
2568     if(SUCCEEDED(hr))
2569     {
2570         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2571         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2572     }
2573
2574     return hr;
2575 }
2576
2577 static inline BOOL is_wellformed(xmlDocPtr doc)
2578 {
2579 #ifdef HAVE_XMLDOC_PROPERTIES
2580     return doc->properties & XML_DOC_WELLFORMED;
2581 #else
2582     /* Not a full check, but catches the worst violations */
2583     xmlNodePtr child;
2584     int root = 0;
2585
2586     for (child = doc->children; child != NULL; child = child->next)
2587     {
2588         switch (child->type)
2589         {
2590         case XML_ELEMENT_NODE:
2591             if (++root > 1)
2592                 return FALSE;
2593             break;
2594         case XML_TEXT_NODE:
2595         case XML_CDATA_SECTION_NODE:
2596             return FALSE;
2597             break;
2598         default:
2599             break;
2600         }
2601     }
2602
2603     return root == 1;
2604 #endif
2605 }
2606
2607 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2608 {
2609     va_list ap;
2610     va_start(ap, msg);
2611     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2612     va_end(ap);
2613 }
2614
2615 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2616 {
2617     va_list ap;
2618     va_start(ap, msg);
2619     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2620     va_end(ap);
2621 }
2622
2623 static HRESULT WINAPI domdoc_validateNode(
2624     IXMLDOMDocument3* iface,
2625     IXMLDOMNode* node,
2626     IXMLDOMParseError** err)
2627 {
2628     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2629     LONG state, err_code = 0;
2630     HRESULT hr = S_OK;
2631     int validated = 0;
2632
2633     TRACE("(%p)->(%p, %p)\n", This, node, err);
2634     domdoc_get_readyState(iface, &state);
2635     if (state != READYSTATE_COMPLETE)
2636     {
2637         if (err)
2638            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2639         return E_PENDING;
2640     }
2641
2642     if (!node)
2643     {
2644         if (err)
2645             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2646         return E_POINTER;
2647     }
2648
2649     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2650     {
2651         if (err)
2652             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2653         return E_FAIL;
2654     }
2655
2656     if (!is_wellformed(get_doc(This)))
2657     {
2658         ERR("doc not well-formed\n");
2659         if (err)
2660             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2661         return S_FALSE;
2662     }
2663
2664     /* DTD validation */
2665     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2666     {
2667         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2668         vctx->error = validate_error;
2669         vctx->warning = validate_warning;
2670         ++validated;
2671
2672         if (!((node == (IXMLDOMNode*)iface)?
2673               xmlValidateDocument(vctx, get_doc(This)) :
2674               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2675         {
2676             /* TODO: get a real error code here */
2677             TRACE("DTD validation failed\n");
2678             err_code = E_XML_INVALID;
2679             hr = S_FALSE;
2680         }
2681         xmlFreeValidCtxt(vctx);
2682     }
2683
2684     /* Schema validation */
2685     if (hr == S_OK && This->properties->schemaCache != NULL)
2686     {
2687
2688         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2689         if (SUCCEEDED(hr))
2690         {
2691             ++validated;
2692             /* TODO: get a real error code here */
2693             if (hr == S_OK)
2694             {
2695                 TRACE("schema validation succeeded\n");
2696             }
2697             else
2698             {
2699                 ERR("schema validation failed\n");
2700                 err_code = E_XML_INVALID;
2701             }
2702         }
2703         else
2704         {
2705             /* not really OK, just didn't find a schema for the ns */
2706             hr = S_OK;
2707         }
2708     }
2709
2710     if (!validated)
2711     {
2712         ERR("no DTD or schema found\n");
2713         err_code = E_XML_NODTD;
2714         hr = S_FALSE;
2715     }
2716
2717     if (err)
2718         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2719
2720     return hr;
2721 }
2722
2723 static HRESULT WINAPI domdoc_validate(
2724     IXMLDOMDocument3* iface,
2725     IXMLDOMParseError** err)
2726 {
2727     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2728     TRACE("(%p)->(%p)\n", This, err);
2729     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2730 }
2731
2732 static HRESULT WINAPI domdoc_setProperty(
2733     IXMLDOMDocument3* iface,
2734     BSTR p,
2735     VARIANT var)
2736 {
2737     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2738
2739     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2740
2741     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2742     {
2743         VARIANT varStr;
2744         HRESULT hr;
2745         BSTR bstr;
2746
2747         V_VT(&varStr) = VT_EMPTY;
2748         if (V_VT(&var) != VT_BSTR)
2749         {
2750             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2751                 return hr;
2752             bstr = V_BSTR(&varStr);
2753         }
2754         else
2755             bstr = V_BSTR(&var);
2756
2757         hr = S_OK;
2758         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2759             This->properties->XPath = TRUE;
2760         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2761             This->properties->XPath = FALSE;
2762         else
2763             hr = E_FAIL;
2764
2765         VariantClear(&varStr);
2766         return hr;
2767     }
2768     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2769     {
2770         VARIANT varStr;
2771         HRESULT hr;
2772         BSTR bstr;
2773         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2774         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2775         xmlXPathContextPtr ctx;
2776         struct list *pNsList;
2777         select_ns_entry* pNsEntry = NULL;
2778
2779         V_VT(&varStr) = VT_EMPTY;
2780         if (V_VT(&var) != VT_BSTR)
2781         {
2782             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2783                 return hr;
2784             bstr = V_BSTR(&varStr);
2785         }
2786         else
2787             bstr = V_BSTR(&var);
2788
2789         hr = S_OK;
2790
2791         pNsList = &(This->properties->selectNsList);
2792         clear_selectNsList(pNsList);
2793         heap_free(nsStr);
2794         nsStr = xmlchar_from_wchar(bstr);
2795
2796         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2797
2798         This->properties->selectNsStr = nsStr;
2799         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2800         if (bstr && *bstr)
2801         {
2802             ctx = xmlXPathNewContext(This->node.node->doc);
2803             pTokBegin = nsStr;
2804             for (; *pTokBegin; pTokBegin = pTokEnd)
2805             {
2806                 if (pNsEntry != NULL)
2807                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2808                 else
2809                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2810
2811                 while (*pTokBegin == ' ')
2812                     ++pTokBegin;
2813                 pTokEnd = pTokBegin;
2814                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2815                     ++pTokEnd;
2816
2817                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2818                 {
2819                     hr = E_FAIL;
2820                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2821                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2822                     continue;
2823                 }
2824
2825                 pTokBegin += 5;
2826                 if (*pTokBegin == '=')
2827                 {
2828                     /*valid for XSLPattern?*/
2829                     FIXME("Setting default xmlns not supported - skipping.\n");
2830                     continue;
2831                 }
2832                 else if (*pTokBegin == ':')
2833                 {
2834                     pNsEntry->prefix = ++pTokBegin;
2835                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2836                         ;
2837
2838                     if (pTokInner == pTokEnd)
2839                     {
2840                         hr = E_FAIL;
2841                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2842                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2843                         continue;
2844                     }
2845
2846                     pNsEntry->prefix_end = *pTokInner;
2847                     *pTokInner = 0;
2848                     ++pTokInner;
2849
2850                     if (pTokEnd-pTokInner > 1 &&
2851                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2852                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2853                     {
2854                         pNsEntry->href = ++pTokInner;
2855                         pNsEntry->href_end = *(pTokEnd-1);
2856                         *(pTokEnd-1) = 0;
2857                         list_add_tail(pNsList, &pNsEntry->entry);
2858                         /*let libxml figure out if they're valid from here ;)*/
2859                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2860                         {
2861                             hr = E_FAIL;
2862                         }
2863                         pNsEntry = NULL;
2864                         continue;
2865                     }
2866                     else
2867                     {
2868                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2869                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2870                         list_add_tail(pNsList, &pNsEntry->entry);
2871
2872                         pNsEntry = NULL;
2873                         hr = E_FAIL;
2874                         continue;
2875                     }
2876                 }
2877                 else
2878                 {
2879                     hr = E_FAIL;
2880                     continue;
2881                 }
2882             }
2883             heap_free(pNsEntry);
2884             xmlXPathFreeContext(ctx);
2885         }
2886
2887         VariantClear(&varStr);
2888         return hr;
2889     }
2890     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2891              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2892              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2893     {
2894         /* Ignore */
2895         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2896         return S_OK;
2897     }
2898
2899     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2900     return E_FAIL;
2901 }
2902
2903 static HRESULT WINAPI domdoc_getProperty(
2904     IXMLDOMDocument3* iface,
2905     BSTR p,
2906     VARIANT* var)
2907 {
2908     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2909
2910     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2911
2912     if (!var)
2913         return E_INVALIDARG;
2914
2915     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2916     {
2917         V_VT(var) = VT_BSTR;
2918         V_BSTR(var) = This->properties->XPath ?
2919                       SysAllocString(PropValueXPathW) :
2920                       SysAllocString(PropValueXSLPatternW);
2921         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2922     }
2923     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2924     {
2925         int lenA, lenW;
2926         BSTR rebuiltStr, cur;
2927         const xmlChar *nsStr;
2928         struct list *pNsList;
2929         select_ns_entry* pNsEntry;
2930
2931         V_VT(var) = VT_BSTR;
2932         nsStr = This->properties->selectNsStr;
2933         pNsList = &This->properties->selectNsList;
2934         lenA = This->properties->selectNsStr_len;
2935         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2936         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2937         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2938         cur = rebuiltStr;
2939         /* this is fine because all of the chars that end tokens are ASCII*/
2940         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2941         {
2942             while (*cur != 0) ++cur;
2943             if (pNsEntry->prefix_end)
2944             {
2945                 *cur = pNsEntry->prefix_end;
2946                 while (*cur != 0) ++cur;
2947             }
2948
2949             if (pNsEntry->href_end)
2950             {
2951                 *cur = pNsEntry->href_end;
2952             }
2953         }
2954         V_BSTR(var) = SysAllocString(rebuiltStr);
2955         heap_free(rebuiltStr);
2956         return S_OK;
2957     }
2958
2959     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2960     return E_FAIL;
2961 }
2962
2963 static HRESULT WINAPI domdoc_importNode(
2964     IXMLDOMDocument3* iface,
2965     IXMLDOMNode* node,
2966     VARIANT_BOOL deep,
2967     IXMLDOMNode** clone)
2968 {
2969     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2970     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2971     return E_NOTIMPL;
2972 }
2973
2974 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2975 {
2976     domdoc_QueryInterface,
2977     domdoc_AddRef,
2978     domdoc_Release,
2979     domdoc_GetTypeInfoCount,
2980     domdoc_GetTypeInfo,
2981     domdoc_GetIDsOfNames,
2982     domdoc_Invoke,
2983     domdoc_get_nodeName,
2984     domdoc_get_nodeValue,
2985     domdoc_put_nodeValue,
2986     domdoc_get_nodeType,
2987     domdoc_get_parentNode,
2988     domdoc_get_childNodes,
2989     domdoc_get_firstChild,
2990     domdoc_get_lastChild,
2991     domdoc_get_previousSibling,
2992     domdoc_get_nextSibling,
2993     domdoc_get_attributes,
2994     domdoc_insertBefore,
2995     domdoc_replaceChild,
2996     domdoc_removeChild,
2997     domdoc_appendChild,
2998     domdoc_hasChildNodes,
2999     domdoc_get_ownerDocument,
3000     domdoc_cloneNode,
3001     domdoc_get_nodeTypeString,
3002     domdoc_get_text,
3003     domdoc_put_text,
3004     domdoc_get_specified,
3005     domdoc_get_definition,
3006     domdoc_get_nodeTypedValue,
3007     domdoc_put_nodeTypedValue,
3008     domdoc_get_dataType,
3009     domdoc_put_dataType,
3010     domdoc_get_xml,
3011     domdoc_transformNode,
3012     domdoc_selectNodes,
3013     domdoc_selectSingleNode,
3014     domdoc_get_parsed,
3015     domdoc_get_namespaceURI,
3016     domdoc_get_prefix,
3017     domdoc_get_baseName,
3018     domdoc_transformNodeToObject,
3019     domdoc_get_doctype,
3020     domdoc_get_implementation,
3021     domdoc_get_documentElement,
3022     domdoc_put_documentElement,
3023     domdoc_createElement,
3024     domdoc_createDocumentFragment,
3025     domdoc_createTextNode,
3026     domdoc_createComment,
3027     domdoc_createCDATASection,
3028     domdoc_createProcessingInstruction,
3029     domdoc_createAttribute,
3030     domdoc_createEntityReference,
3031     domdoc_getElementsByTagName,
3032     domdoc_createNode,
3033     domdoc_nodeFromID,
3034     domdoc_load,
3035     domdoc_get_readyState,
3036     domdoc_get_parseError,
3037     domdoc_get_url,
3038     domdoc_get_async,
3039     domdoc_put_async,
3040     domdoc_abort,
3041     domdoc_loadXML,
3042     domdoc_save,
3043     domdoc_get_validateOnParse,
3044     domdoc_put_validateOnParse,
3045     domdoc_get_resolveExternals,
3046     domdoc_put_resolveExternals,
3047     domdoc_get_preserveWhiteSpace,
3048     domdoc_put_preserveWhiteSpace,
3049     domdoc_put_onreadystatechange,
3050     domdoc_put_onDataAvailable,
3051     domdoc_put_onTransformNode,
3052     domdoc_get_namespaces,
3053     domdoc_get_schemas,
3054     domdoc_putref_schemas,
3055     domdoc_validate,
3056     domdoc_setProperty,
3057     domdoc_getProperty,
3058     domdoc_validateNode,
3059     domdoc_importNode
3060 };
3061
3062 /* IConnectionPointContainer */
3063 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3064                                                               REFIID riid, void **ppv)
3065 {
3066     domdoc *This = impl_from_IConnectionPointContainer(iface);
3067     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3068 }
3069
3070 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3071 {
3072     domdoc *This = impl_from_IConnectionPointContainer(iface);
3073     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3074 }
3075
3076 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3077 {
3078     domdoc *This = impl_from_IConnectionPointContainer(iface);
3079     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3080 }
3081
3082 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3083         IEnumConnectionPoints **ppEnum)
3084 {
3085     domdoc *This = impl_from_IConnectionPointContainer(iface);
3086     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3087     return E_NOTIMPL;
3088 }
3089
3090 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3091         REFIID riid, IConnectionPoint **cp)
3092 {
3093     domdoc *This = impl_from_IConnectionPointContainer(iface);
3094     ConnectionPoint *iter;
3095
3096     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3097
3098     *cp = NULL;
3099
3100     for(iter = This->cp_list; iter; iter = iter->next)
3101     {
3102         if (IsEqualGUID(iter->iid, riid))
3103             *cp = &iter->IConnectionPoint_iface;
3104     }
3105
3106     if (*cp)
3107     {
3108         IConnectionPoint_AddRef(*cp);
3109         return S_OK;
3110     }
3111
3112     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3113     return CONNECT_E_NOCONNECTION;
3114
3115 }
3116
3117 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3118 {
3119     ConnectionPointContainer_QueryInterface,
3120     ConnectionPointContainer_AddRef,
3121     ConnectionPointContainer_Release,
3122     ConnectionPointContainer_EnumConnectionPoints,
3123     ConnectionPointContainer_FindConnectionPoint
3124 };
3125
3126 /* IConnectionPoint */
3127 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3128                                                      REFIID riid, void **ppv)
3129 {
3130     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3131
3132     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3133
3134     *ppv = NULL;
3135
3136     if (IsEqualGUID(&IID_IUnknown, riid) ||
3137         IsEqualGUID(&IID_IConnectionPoint, riid))
3138     {
3139         *ppv = iface;
3140     }
3141
3142     if (*ppv)
3143     {
3144         IConnectionPoint_AddRef(iface);
3145         return S_OK;
3146     }
3147
3148     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3149     return E_NOINTERFACE;
3150 }
3151
3152 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3153 {
3154     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3155     return IConnectionPointContainer_AddRef(This->container);
3156 }
3157
3158 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3159 {
3160     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3161     return IConnectionPointContainer_Release(This->container);
3162 }
3163
3164 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3165 {
3166     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3167
3168     TRACE("(%p)->(%p)\n", This, iid);
3169
3170     if (!iid) return E_POINTER;
3171
3172     *iid = *This->iid;
3173     return S_OK;
3174 }
3175
3176 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3177         IConnectionPointContainer **container)
3178 {
3179     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3180
3181     TRACE("(%p)->(%p)\n", This, container);
3182
3183     if (!container) return E_POINTER;
3184
3185     *container = This->container;
3186     IConnectionPointContainer_AddRef(*container);
3187     return S_OK;
3188 }
3189
3190 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3191                                              DWORD *pdwCookie)
3192 {
3193     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3194     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3195     return E_NOTIMPL;
3196 }
3197
3198 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3199 {
3200     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3201
3202     TRACE("(%p)->(%d)\n", This, cookie);
3203
3204     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3205         return CONNECT_E_NOCONNECTION;
3206
3207     IUnknown_Release(This->sinks[cookie-1].unk);
3208     This->sinks[cookie-1].unk = NULL;
3209
3210     return S_OK;
3211 }
3212
3213 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3214                                                       IEnumConnections **ppEnum)
3215 {
3216     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3217     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3218     return E_NOTIMPL;
3219 }
3220
3221 static const IConnectionPointVtbl ConnectionPointVtbl =
3222 {
3223     ConnectionPoint_QueryInterface,
3224     ConnectionPoint_AddRef,
3225     ConnectionPoint_Release,
3226     ConnectionPoint_GetConnectionInterface,
3227     ConnectionPoint_GetConnectionPointContainer,
3228     ConnectionPoint_Advise,
3229     ConnectionPoint_Unadvise,
3230     ConnectionPoint_EnumConnections
3231 };
3232
3233 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3234 {
3235     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3236     cp->doc = doc;
3237     cp->iid = riid;
3238     cp->sinks = NULL;
3239     cp->sinks_size = 0;
3240
3241     cp->next = doc->cp_list;
3242     doc->cp_list = cp;
3243
3244     cp->container = &doc->IConnectionPointContainer_iface;
3245 }
3246
3247 /* domdoc implementation of IObjectWithSite */
3248 static HRESULT WINAPI
3249 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3250 {
3251     domdoc *This = impl_from_IObjectWithSite(iface);
3252     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3253 }
3254
3255 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3256 {
3257     domdoc *This = impl_from_IObjectWithSite(iface);
3258     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3259 }
3260
3261 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3262 {
3263     domdoc *This = impl_from_IObjectWithSite(iface);
3264     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3265 }
3266
3267 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3268 {
3269     domdoc *This = impl_from_IObjectWithSite(iface);
3270
3271     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3272
3273     if ( !This->site )
3274         return E_FAIL;
3275
3276     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3277 }
3278
3279 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3280 {
3281     domdoc *This = impl_from_IObjectWithSite(iface);
3282
3283     TRACE("(%p)->(%p)\n", iface, punk);
3284
3285     if(!punk)
3286     {
3287         if(This->site)
3288         {
3289             IUnknown_Release( This->site );
3290             This->site = NULL;
3291         }
3292
3293         return S_OK;
3294     }
3295
3296     IUnknown_AddRef( punk );
3297
3298     if(This->site)
3299         IUnknown_Release( This->site );
3300
3301     This->site = punk;
3302
3303     return S_OK;
3304 }
3305
3306 static const IObjectWithSiteVtbl domdocObjectSite =
3307 {
3308     domdoc_ObjectWithSite_QueryInterface,
3309     domdoc_ObjectWithSite_AddRef,
3310     domdoc_ObjectWithSite_Release,
3311     domdoc_ObjectWithSite_SetSite,
3312     domdoc_ObjectWithSite_GetSite
3313 };
3314
3315 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3316 {
3317     domdoc *This = impl_from_IObjectSafety(iface);
3318     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3319 }
3320
3321 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3322 {
3323     domdoc *This = impl_from_IObjectSafety(iface);
3324     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3325 }
3326
3327 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3328 {
3329     domdoc *This = impl_from_IObjectSafety(iface);
3330     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3331 }
3332
3333 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3334
3335 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3336         DWORD *supported, DWORD *enabled)
3337 {
3338     domdoc *This = impl_from_IObjectSafety(iface);
3339
3340     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3341
3342     if(!supported || !enabled) return E_POINTER;
3343
3344     *supported = SAFETY_SUPPORTED_OPTIONS;
3345     *enabled = This->safeopt;
3346
3347     return S_OK;
3348 }
3349
3350 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3351         DWORD mask, DWORD enabled)
3352 {
3353     domdoc *This = impl_from_IObjectSafety(iface);
3354     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3355
3356     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3357         return E_FAIL;
3358
3359     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3360
3361     return S_OK;
3362 }
3363
3364 #undef SAFETY_SUPPORTED_OPTIONS
3365
3366 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3367     domdoc_Safety_QueryInterface,
3368     domdoc_Safety_AddRef,
3369     domdoc_Safety_Release,
3370     domdoc_Safety_GetInterfaceSafetyOptions,
3371     domdoc_Safety_SetInterfaceSafetyOptions
3372 };
3373
3374 static const tid_t domdoc_iface_tids[] = {
3375     IXMLDOMDocument3_tid,
3376     0
3377 };
3378
3379 static dispex_static_data_t domdoc_dispex = {
3380     NULL,
3381     IXMLDOMDocument3_tid,
3382     NULL,
3383     domdoc_iface_tids
3384 };
3385
3386 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3387 {
3388     domdoc *doc;
3389
3390     doc = heap_alloc( sizeof (*doc) );
3391     if( !doc )
3392         return E_OUTOFMEMORY;
3393
3394     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3395     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3396     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3397     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3398     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3399     doc->ref = 1;
3400     doc->async = VARIANT_TRUE;
3401     doc->validating = 0;
3402     doc->resolving = 0;
3403     doc->properties = properties_from_xmlDocPtr(xmldoc);
3404     doc->error = S_OK;
3405     doc->stream = NULL;
3406     doc->site = NULL;
3407     doc->safeopt = 0;
3408     doc->bsc = NULL;
3409     doc->cp_list = NULL;
3410     memset(doc->events, 0, sizeof(doc->events));
3411
3412     /* events connection points */
3413     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3414     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3415     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3416
3417     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3418             &domdoc_dispex);
3419
3420     *document = &doc->IXMLDOMDocument3_iface;
3421
3422     TRACE("returning iface %p\n", *document);
3423     return S_OK;
3424 }
3425
3426 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3427 {
3428     xmlDocPtr xmldoc;
3429     HRESULT hr;
3430
3431     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3432
3433     xmldoc = xmlNewDoc(NULL);
3434     if(!xmldoc)
3435         return E_OUTOFMEMORY;
3436
3437     xmldoc->_private = create_priv();
3438     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3439
3440     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3441     if(FAILED(hr))
3442     {
3443         free_properties(properties_from_xmlDocPtr(xmldoc));
3444         heap_free(xmldoc->_private);
3445         xmlFreeDoc(xmldoc);
3446         return hr;
3447     }
3448
3449     return hr;
3450 }
3451
3452 IUnknown* create_domdoc( xmlNodePtr document )
3453 {
3454     void* pObj = NULL;
3455     HRESULT hr;
3456
3457     TRACE("(%p)\n", document);
3458
3459     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3460     if (FAILED(hr))
3461         return NULL;
3462
3463     return pObj;
3464 }
3465
3466 #else
3467
3468 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3469 {
3470     MESSAGE("This program tried to use a DOMDocument object, but\n"
3471             "libxml2 support was not present at compile time.\n");
3472     return E_NOTIMPL;
3473 }
3474
3475 #endif