mshtml: Added IOleContainer::EnumObjects tests.
[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         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2771         struct list *pNsList;
2772         VARIANT varStr;
2773         HRESULT hr;
2774         BSTR bstr;
2775
2776         V_VT(&varStr) = VT_EMPTY;
2777         if (V_VT(&var) != VT_BSTR)
2778         {
2779             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2780                 return hr;
2781             bstr = V_BSTR(&varStr);
2782         }
2783         else
2784             bstr = V_BSTR(&var);
2785
2786         hr = S_OK;
2787
2788         pNsList = &(This->properties->selectNsList);
2789         clear_selectNsList(pNsList);
2790         heap_free(nsStr);
2791         nsStr = xmlchar_from_wchar(bstr);
2792
2793         TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2794
2795         This->properties->selectNsStr = nsStr;
2796         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2797         if (bstr && *bstr)
2798         {
2799             xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2800             select_ns_entry* ns_entry = NULL;
2801             xmlXPathContextPtr ctx;
2802
2803             ctx = xmlXPathNewContext(This->node.node->doc);
2804             pTokBegin = nsStr;
2805
2806             /* skip leading spaces */
2807             while (*pTokBegin == ' '  || *pTokBegin == '\n' ||
2808                    *pTokBegin == '\t' || *pTokBegin == '\r')
2809                 ++pTokBegin;
2810
2811             for (; *pTokBegin; pTokBegin = pTokEnd)
2812             {
2813                 if (ns_entry)
2814                     memset(ns_entry, 0, sizeof(select_ns_entry));
2815                 else
2816                     ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2817
2818                 while (*pTokBegin == ' ')
2819                     ++pTokBegin;
2820                 pTokEnd = pTokBegin;
2821                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2822                     ++pTokEnd;
2823
2824                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2825                 {
2826                     hr = E_FAIL;
2827                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2828                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2829                     continue;
2830                 }
2831
2832                 pTokBegin += 5;
2833                 if (*pTokBegin == '=')
2834                 {
2835                     /*valid for XSLPattern?*/
2836                     FIXME("Setting default xmlns not supported - skipping.\n");
2837                     continue;
2838                 }
2839                 else if (*pTokBegin == ':')
2840                 {
2841                     ns_entry->prefix = ++pTokBegin;
2842                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2843                         ;
2844
2845                     if (pTokInner == pTokEnd)
2846                     {
2847                         hr = E_FAIL;
2848                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2849                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2850                         continue;
2851                     }
2852
2853                     ns_entry->prefix_end = *pTokInner;
2854                     *pTokInner = 0;
2855                     ++pTokInner;
2856
2857                     if (pTokEnd-pTokInner > 1 &&
2858                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2859                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2860                     {
2861                         ns_entry->href = ++pTokInner;
2862                         ns_entry->href_end = *(pTokEnd-1);
2863                         *(pTokEnd-1) = 0;
2864                         list_add_tail(pNsList, &ns_entry->entry);
2865                         /*let libxml figure out if they're valid from here ;)*/
2866                         if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2867                         {
2868                             hr = E_FAIL;
2869                         }
2870                         ns_entry = NULL;
2871                         continue;
2872                     }
2873                     else
2874                     {
2875                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2876                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2877                         list_add_tail(pNsList, &ns_entry->entry);
2878
2879                         ns_entry = NULL;
2880                         hr = E_FAIL;
2881                         continue;
2882                     }
2883                 }
2884                 else
2885                 {
2886                     hr = E_FAIL;
2887                     continue;
2888                 }
2889             }
2890             heap_free(ns_entry);
2891             xmlXPathFreeContext(ctx);
2892         }
2893
2894         VariantClear(&varStr);
2895         return hr;
2896     }
2897     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2898              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2899              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2900     {
2901         /* Ignore */
2902         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2903         return S_OK;
2904     }
2905
2906     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2907     return E_FAIL;
2908 }
2909
2910 static HRESULT WINAPI domdoc_getProperty(
2911     IXMLDOMDocument3* iface,
2912     BSTR p,
2913     VARIANT* var)
2914 {
2915     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2916
2917     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2918
2919     if (!var)
2920         return E_INVALIDARG;
2921
2922     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2923     {
2924         V_VT(var) = VT_BSTR;
2925         V_BSTR(var) = This->properties->XPath ?
2926                       SysAllocString(PropValueXPathW) :
2927                       SysAllocString(PropValueXSLPatternW);
2928         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2929     }
2930     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2931     {
2932         int lenA, lenW;
2933         BSTR rebuiltStr, cur;
2934         const xmlChar *nsStr;
2935         struct list *pNsList;
2936         select_ns_entry* pNsEntry;
2937
2938         V_VT(var) = VT_BSTR;
2939         nsStr = This->properties->selectNsStr;
2940         pNsList = &This->properties->selectNsList;
2941         lenA = This->properties->selectNsStr_len;
2942         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2943         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2944         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2945         cur = rebuiltStr;
2946         /* this is fine because all of the chars that end tokens are ASCII*/
2947         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2948         {
2949             while (*cur != 0) ++cur;
2950             if (pNsEntry->prefix_end)
2951             {
2952                 *cur = pNsEntry->prefix_end;
2953                 while (*cur != 0) ++cur;
2954             }
2955
2956             if (pNsEntry->href_end)
2957             {
2958                 *cur = pNsEntry->href_end;
2959             }
2960         }
2961         V_BSTR(var) = SysAllocString(rebuiltStr);
2962         heap_free(rebuiltStr);
2963         return S_OK;
2964     }
2965
2966     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2967     return E_FAIL;
2968 }
2969
2970 static HRESULT WINAPI domdoc_importNode(
2971     IXMLDOMDocument3* iface,
2972     IXMLDOMNode* node,
2973     VARIANT_BOOL deep,
2974     IXMLDOMNode** clone)
2975 {
2976     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2977     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2978     return E_NOTIMPL;
2979 }
2980
2981 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2982 {
2983     domdoc_QueryInterface,
2984     domdoc_AddRef,
2985     domdoc_Release,
2986     domdoc_GetTypeInfoCount,
2987     domdoc_GetTypeInfo,
2988     domdoc_GetIDsOfNames,
2989     domdoc_Invoke,
2990     domdoc_get_nodeName,
2991     domdoc_get_nodeValue,
2992     domdoc_put_nodeValue,
2993     domdoc_get_nodeType,
2994     domdoc_get_parentNode,
2995     domdoc_get_childNodes,
2996     domdoc_get_firstChild,
2997     domdoc_get_lastChild,
2998     domdoc_get_previousSibling,
2999     domdoc_get_nextSibling,
3000     domdoc_get_attributes,
3001     domdoc_insertBefore,
3002     domdoc_replaceChild,
3003     domdoc_removeChild,
3004     domdoc_appendChild,
3005     domdoc_hasChildNodes,
3006     domdoc_get_ownerDocument,
3007     domdoc_cloneNode,
3008     domdoc_get_nodeTypeString,
3009     domdoc_get_text,
3010     domdoc_put_text,
3011     domdoc_get_specified,
3012     domdoc_get_definition,
3013     domdoc_get_nodeTypedValue,
3014     domdoc_put_nodeTypedValue,
3015     domdoc_get_dataType,
3016     domdoc_put_dataType,
3017     domdoc_get_xml,
3018     domdoc_transformNode,
3019     domdoc_selectNodes,
3020     domdoc_selectSingleNode,
3021     domdoc_get_parsed,
3022     domdoc_get_namespaceURI,
3023     domdoc_get_prefix,
3024     domdoc_get_baseName,
3025     domdoc_transformNodeToObject,
3026     domdoc_get_doctype,
3027     domdoc_get_implementation,
3028     domdoc_get_documentElement,
3029     domdoc_put_documentElement,
3030     domdoc_createElement,
3031     domdoc_createDocumentFragment,
3032     domdoc_createTextNode,
3033     domdoc_createComment,
3034     domdoc_createCDATASection,
3035     domdoc_createProcessingInstruction,
3036     domdoc_createAttribute,
3037     domdoc_createEntityReference,
3038     domdoc_getElementsByTagName,
3039     domdoc_createNode,
3040     domdoc_nodeFromID,
3041     domdoc_load,
3042     domdoc_get_readyState,
3043     domdoc_get_parseError,
3044     domdoc_get_url,
3045     domdoc_get_async,
3046     domdoc_put_async,
3047     domdoc_abort,
3048     domdoc_loadXML,
3049     domdoc_save,
3050     domdoc_get_validateOnParse,
3051     domdoc_put_validateOnParse,
3052     domdoc_get_resolveExternals,
3053     domdoc_put_resolveExternals,
3054     domdoc_get_preserveWhiteSpace,
3055     domdoc_put_preserveWhiteSpace,
3056     domdoc_put_onreadystatechange,
3057     domdoc_put_onDataAvailable,
3058     domdoc_put_onTransformNode,
3059     domdoc_get_namespaces,
3060     domdoc_get_schemas,
3061     domdoc_putref_schemas,
3062     domdoc_validate,
3063     domdoc_setProperty,
3064     domdoc_getProperty,
3065     domdoc_validateNode,
3066     domdoc_importNode
3067 };
3068
3069 /* IConnectionPointContainer */
3070 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3071                                                               REFIID riid, void **ppv)
3072 {
3073     domdoc *This = impl_from_IConnectionPointContainer(iface);
3074     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3075 }
3076
3077 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3078 {
3079     domdoc *This = impl_from_IConnectionPointContainer(iface);
3080     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3081 }
3082
3083 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3084 {
3085     domdoc *This = impl_from_IConnectionPointContainer(iface);
3086     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3087 }
3088
3089 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3090         IEnumConnectionPoints **ppEnum)
3091 {
3092     domdoc *This = impl_from_IConnectionPointContainer(iface);
3093     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3094     return E_NOTIMPL;
3095 }
3096
3097 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3098         REFIID riid, IConnectionPoint **cp)
3099 {
3100     domdoc *This = impl_from_IConnectionPointContainer(iface);
3101     ConnectionPoint *iter;
3102
3103     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3104
3105     *cp = NULL;
3106
3107     for(iter = This->cp_list; iter; iter = iter->next)
3108     {
3109         if (IsEqualGUID(iter->iid, riid))
3110             *cp = &iter->IConnectionPoint_iface;
3111     }
3112
3113     if (*cp)
3114     {
3115         IConnectionPoint_AddRef(*cp);
3116         return S_OK;
3117     }
3118
3119     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3120     return CONNECT_E_NOCONNECTION;
3121
3122 }
3123
3124 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3125 {
3126     ConnectionPointContainer_QueryInterface,
3127     ConnectionPointContainer_AddRef,
3128     ConnectionPointContainer_Release,
3129     ConnectionPointContainer_EnumConnectionPoints,
3130     ConnectionPointContainer_FindConnectionPoint
3131 };
3132
3133 /* IConnectionPoint */
3134 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3135                                                      REFIID riid, void **ppv)
3136 {
3137     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3138
3139     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3140
3141     *ppv = NULL;
3142
3143     if (IsEqualGUID(&IID_IUnknown, riid) ||
3144         IsEqualGUID(&IID_IConnectionPoint, riid))
3145     {
3146         *ppv = iface;
3147     }
3148
3149     if (*ppv)
3150     {
3151         IConnectionPoint_AddRef(iface);
3152         return S_OK;
3153     }
3154
3155     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3156     return E_NOINTERFACE;
3157 }
3158
3159 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3160 {
3161     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3162     return IConnectionPointContainer_AddRef(This->container);
3163 }
3164
3165 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3166 {
3167     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3168     return IConnectionPointContainer_Release(This->container);
3169 }
3170
3171 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3172 {
3173     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3174
3175     TRACE("(%p)->(%p)\n", This, iid);
3176
3177     if (!iid) return E_POINTER;
3178
3179     *iid = *This->iid;
3180     return S_OK;
3181 }
3182
3183 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3184         IConnectionPointContainer **container)
3185 {
3186     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3187
3188     TRACE("(%p)->(%p)\n", This, container);
3189
3190     if (!container) return E_POINTER;
3191
3192     *container = This->container;
3193     IConnectionPointContainer_AddRef(*container);
3194     return S_OK;
3195 }
3196
3197 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3198                                              DWORD *pdwCookie)
3199 {
3200     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3201     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3202     return E_NOTIMPL;
3203 }
3204
3205 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3206 {
3207     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3208
3209     TRACE("(%p)->(%d)\n", This, cookie);
3210
3211     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3212         return CONNECT_E_NOCONNECTION;
3213
3214     IUnknown_Release(This->sinks[cookie-1].unk);
3215     This->sinks[cookie-1].unk = NULL;
3216
3217     return S_OK;
3218 }
3219
3220 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3221                                                       IEnumConnections **ppEnum)
3222 {
3223     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3224     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3225     return E_NOTIMPL;
3226 }
3227
3228 static const IConnectionPointVtbl ConnectionPointVtbl =
3229 {
3230     ConnectionPoint_QueryInterface,
3231     ConnectionPoint_AddRef,
3232     ConnectionPoint_Release,
3233     ConnectionPoint_GetConnectionInterface,
3234     ConnectionPoint_GetConnectionPointContainer,
3235     ConnectionPoint_Advise,
3236     ConnectionPoint_Unadvise,
3237     ConnectionPoint_EnumConnections
3238 };
3239
3240 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3241 {
3242     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3243     cp->doc = doc;
3244     cp->iid = riid;
3245     cp->sinks = NULL;
3246     cp->sinks_size = 0;
3247
3248     cp->next = doc->cp_list;
3249     doc->cp_list = cp;
3250
3251     cp->container = &doc->IConnectionPointContainer_iface;
3252 }
3253
3254 /* domdoc implementation of IObjectWithSite */
3255 static HRESULT WINAPI
3256 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3257 {
3258     domdoc *This = impl_from_IObjectWithSite(iface);
3259     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3260 }
3261
3262 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3263 {
3264     domdoc *This = impl_from_IObjectWithSite(iface);
3265     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3266 }
3267
3268 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3269 {
3270     domdoc *This = impl_from_IObjectWithSite(iface);
3271     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3272 }
3273
3274 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3275 {
3276     domdoc *This = impl_from_IObjectWithSite(iface);
3277
3278     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3279
3280     if ( !This->site )
3281         return E_FAIL;
3282
3283     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3284 }
3285
3286 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3287 {
3288     domdoc *This = impl_from_IObjectWithSite(iface);
3289
3290     TRACE("(%p)->(%p)\n", iface, punk);
3291
3292     if(!punk)
3293     {
3294         if(This->site)
3295         {
3296             IUnknown_Release( This->site );
3297             This->site = NULL;
3298         }
3299
3300         return S_OK;
3301     }
3302
3303     IUnknown_AddRef( punk );
3304
3305     if(This->site)
3306         IUnknown_Release( This->site );
3307
3308     This->site = punk;
3309
3310     return S_OK;
3311 }
3312
3313 static const IObjectWithSiteVtbl domdocObjectSite =
3314 {
3315     domdoc_ObjectWithSite_QueryInterface,
3316     domdoc_ObjectWithSite_AddRef,
3317     domdoc_ObjectWithSite_Release,
3318     domdoc_ObjectWithSite_SetSite,
3319     domdoc_ObjectWithSite_GetSite
3320 };
3321
3322 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3323 {
3324     domdoc *This = impl_from_IObjectSafety(iface);
3325     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3326 }
3327
3328 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3329 {
3330     domdoc *This = impl_from_IObjectSafety(iface);
3331     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3332 }
3333
3334 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3335 {
3336     domdoc *This = impl_from_IObjectSafety(iface);
3337     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3338 }
3339
3340 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3341
3342 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3343         DWORD *supported, DWORD *enabled)
3344 {
3345     domdoc *This = impl_from_IObjectSafety(iface);
3346
3347     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3348
3349     if(!supported || !enabled) return E_POINTER;
3350
3351     *supported = SAFETY_SUPPORTED_OPTIONS;
3352     *enabled = This->safeopt;
3353
3354     return S_OK;
3355 }
3356
3357 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3358         DWORD mask, DWORD enabled)
3359 {
3360     domdoc *This = impl_from_IObjectSafety(iface);
3361     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3362
3363     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3364         return E_FAIL;
3365
3366     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3367
3368     return S_OK;
3369 }
3370
3371 #undef SAFETY_SUPPORTED_OPTIONS
3372
3373 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3374     domdoc_Safety_QueryInterface,
3375     domdoc_Safety_AddRef,
3376     domdoc_Safety_Release,
3377     domdoc_Safety_GetInterfaceSafetyOptions,
3378     domdoc_Safety_SetInterfaceSafetyOptions
3379 };
3380
3381 static const tid_t domdoc_iface_tids[] = {
3382     IXMLDOMDocument3_tid,
3383     0
3384 };
3385
3386 static dispex_static_data_t domdoc_dispex = {
3387     NULL,
3388     IXMLDOMDocument3_tid,
3389     NULL,
3390     domdoc_iface_tids
3391 };
3392
3393 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3394 {
3395     domdoc *doc;
3396
3397     doc = heap_alloc( sizeof (*doc) );
3398     if( !doc )
3399         return E_OUTOFMEMORY;
3400
3401     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3402     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3403     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3404     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3405     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3406     doc->ref = 1;
3407     doc->async = VARIANT_TRUE;
3408     doc->validating = 0;
3409     doc->resolving = 0;
3410     doc->properties = properties_from_xmlDocPtr(xmldoc);
3411     doc->error = S_OK;
3412     doc->stream = NULL;
3413     doc->site = NULL;
3414     doc->safeopt = 0;
3415     doc->bsc = NULL;
3416     doc->cp_list = NULL;
3417     memset(doc->events, 0, sizeof(doc->events));
3418
3419     /* events connection points */
3420     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3421     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3422     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3423
3424     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3425             &domdoc_dispex);
3426
3427     *document = &doc->IXMLDOMDocument3_iface;
3428
3429     TRACE("returning iface %p\n", *document);
3430     return S_OK;
3431 }
3432
3433 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3434 {
3435     xmlDocPtr xmldoc;
3436     HRESULT hr;
3437
3438     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3439
3440     xmldoc = xmlNewDoc(NULL);
3441     if(!xmldoc)
3442         return E_OUTOFMEMORY;
3443
3444     xmldoc->_private = create_priv();
3445     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3446
3447     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3448     if(FAILED(hr))
3449     {
3450         free_properties(properties_from_xmlDocPtr(xmldoc));
3451         heap_free(xmldoc->_private);
3452         xmlFreeDoc(xmldoc);
3453         return hr;
3454     }
3455
3456     return hr;
3457 }
3458
3459 IUnknown* create_domdoc( xmlNodePtr document )
3460 {
3461     void* pObj = NULL;
3462     HRESULT hr;
3463
3464     TRACE("(%p)\n", document);
3465
3466     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3467     if (FAILED(hr))
3468         return NULL;
3469
3470     return pObj;
3471 }
3472
3473 #else
3474
3475 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3476 {
3477     MESSAGE("This program tried to use a DOMDocument object, but\n"
3478             "libxml2 support was not present at compile time.\n");
3479     return E_NOTIMPL;
3480 }
3481
3482 #endif