msxml3: Allocate private data when cloning from existing document.
[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
2086                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2087                 xmldoc->_private = create_priv();
2088                 hr = attach_xmldoc(This, xmldoc);
2089
2090                 if(SUCCEEDED(hr))
2091                     *isSuccessful = VARIANT_TRUE;
2092
2093                 return hr;
2094             }
2095         }
2096         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2097         if(hr == S_OK)
2098         {
2099             IPersistStream *pDocStream;
2100             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2101             if(hr == S_OK)
2102             {
2103                 hr = IPersistStream_Load(pDocStream, pStream);
2104                 IStream_Release(pStream);
2105                 if(hr == S_OK)
2106                 {
2107                     *isSuccessful = VARIANT_TRUE;
2108
2109                     TRACE("Using IStream to load Document\n");
2110                     return S_OK;
2111                 }
2112                 else
2113                 {
2114                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2115                 }
2116             }
2117             else
2118             {
2119                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2120             }
2121         }
2122         else
2123         {
2124             /* ISequentialStream */
2125             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2126         }
2127         break;
2128      default:
2129             FIXME("VT type not supported (%d)\n", V_VT(&source));
2130     }
2131
2132     if ( filename )
2133     {
2134         hr = doread( This, filename );
2135
2136         if ( FAILED(hr) )
2137             This->error = E_FAIL;
2138         else
2139         {
2140             hr = This->error = S_OK;
2141             *isSuccessful = VARIANT_TRUE;
2142         }
2143     }
2144
2145     if(!filename || FAILED(hr)) {
2146         xmldoc = xmlNewDoc(NULL);
2147         xmldoc->_private = create_priv();
2148         hr = attach_xmldoc(This, xmldoc);
2149         if(SUCCEEDED(hr))
2150             hr = S_FALSE;
2151     }
2152
2153     TRACE("ret (%d)\n", hr);
2154
2155     return hr;
2156 }
2157
2158
2159 static HRESULT WINAPI domdoc_get_readyState(
2160     IXMLDOMDocument3 *iface,
2161     LONG *value )
2162 {
2163     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2164     FIXME("stub! (%p)->(%p)\n", This, value);
2165
2166     if (!value)
2167         return E_INVALIDARG;
2168
2169     *value = READYSTATE_COMPLETE;
2170     return S_OK;
2171 }
2172
2173
2174 static HRESULT WINAPI domdoc_get_parseError(
2175     IXMLDOMDocument3 *iface,
2176     IXMLDOMParseError** errorObj )
2177 {
2178     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2179     static const WCHAR err[] = {'e','r','r','o','r',0};
2180     BSTR error_string = NULL;
2181
2182     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2183
2184     if(This->error)
2185         error_string = SysAllocString(err);
2186
2187     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2188     if(!*errorObj) return E_OUTOFMEMORY;
2189     return S_OK;
2190 }
2191
2192
2193 static HRESULT WINAPI domdoc_get_url(
2194     IXMLDOMDocument3 *iface,
2195     BSTR* urlString )
2196 {
2197     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2198     FIXME("(%p)->(%p)\n", This, urlString);
2199     return E_NOTIMPL;
2200 }
2201
2202
2203 static HRESULT WINAPI domdoc_get_async(
2204     IXMLDOMDocument3 *iface,
2205     VARIANT_BOOL* isAsync )
2206 {
2207     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2208
2209     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2210     *isAsync = This->async;
2211     return S_OK;
2212 }
2213
2214
2215 static HRESULT WINAPI domdoc_put_async(
2216     IXMLDOMDocument3 *iface,
2217     VARIANT_BOOL isAsync )
2218 {
2219     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2220
2221     TRACE("(%p)->(%d)\n", This, isAsync);
2222     This->async = isAsync;
2223     return S_OK;
2224 }
2225
2226
2227 static HRESULT WINAPI domdoc_abort(
2228     IXMLDOMDocument3 *iface )
2229 {
2230     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2231     FIXME("%p\n", This);
2232     return E_NOTIMPL;
2233 }
2234
2235 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2236 static HRESULT WINAPI domdoc_loadXML(
2237     IXMLDOMDocument3 *iface,
2238     BSTR data,
2239     VARIANT_BOOL* isSuccessful )
2240 {
2241     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2242     xmlDocPtr xmldoc = NULL;
2243     HRESULT hr = S_FALSE, hr2;
2244
2245     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2246
2247     assert ( &This->node );
2248
2249     if ( isSuccessful )
2250     {
2251         *isSuccessful = VARIANT_FALSE;
2252
2253         if (data)
2254         {
2255             WCHAR *ptr = data;
2256
2257             /* skip leading spaces if needed */
2258             if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2259                  while (*ptr)
2260                     if (isspaceW(*ptr)) ptr++; else break;
2261
2262             xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2263             if ( !xmldoc )
2264             {
2265                 This->error = E_FAIL;
2266                 TRACE("failed to parse document\n");
2267             }
2268             else
2269             {
2270                 hr = This->error = S_OK;
2271                 *isSuccessful = VARIANT_TRUE;
2272                 TRACE("parsed document %p\n", xmldoc);
2273             }
2274         }
2275     }
2276     if(!xmldoc)
2277         xmldoc = xmlNewDoc(NULL);
2278
2279     xmldoc->_private = create_priv();
2280
2281     hr2 = attach_xmldoc(This, xmldoc);
2282     if( FAILED(hr2) )
2283         hr = hr2;
2284
2285     return hr;
2286 }
2287
2288 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2289 {
2290     DWORD written = -1;
2291
2292     if(!WriteFile(ctx, buffer, len, &written, NULL))
2293     {
2294         WARN("write error\n");
2295         return -1;
2296     }
2297     else
2298         return written;
2299 }
2300
2301 static int XMLCALL domdoc_save_closecallback(void *ctx)
2302 {
2303     return CloseHandle(ctx) ? 0 : -1;
2304 }
2305
2306 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2307 {
2308     ULONG written = 0;
2309     HRESULT hr;
2310
2311     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2312     if (hr != S_OK)
2313     {
2314         WARN("stream write error: 0x%08x\n", hr);
2315         return -1;
2316     }
2317     else
2318         return written;
2319 }
2320
2321 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2322 {
2323     IStream_Release((IStream*)ctx);
2324     return 0;
2325 }
2326
2327 static HRESULT WINAPI domdoc_save(
2328     IXMLDOMDocument3 *iface,
2329     VARIANT destination )
2330 {
2331     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2332     xmlSaveCtxtPtr ctx = NULL;
2333     xmlNodePtr xmldecl;
2334     HRESULT ret = S_OK;
2335
2336     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2337
2338     switch (V_VT(&destination))
2339     {
2340     case VT_UNKNOWN:
2341         {
2342             IUnknown *pUnk = V_UNKNOWN(&destination);
2343             IXMLDOMDocument3 *document;
2344             IStream *stream;
2345
2346             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2347             if(ret == S_OK)
2348             {
2349                 VARIANT_BOOL success;
2350                 BSTR xml;
2351
2352                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2353                 if(ret == S_OK)
2354                 {
2355                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2356                     SysFreeString(xml);
2357                 }
2358
2359                 IXMLDOMDocument3_Release(document);
2360                 return ret;
2361             }
2362
2363             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2364             if(ret == S_OK)
2365             {
2366                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2367                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2368
2369                 if(!ctx)
2370                 {
2371                     IStream_Release(stream);
2372                     return E_FAIL;
2373                 }
2374             }
2375         }
2376         break;
2377
2378     case VT_BSTR:
2379     case VT_BSTR | VT_BYREF:
2380         {
2381             /* save with file path */
2382             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2383                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2384             if( handle == INVALID_HANDLE_VALUE )
2385             {
2386                 WARN("failed to create file\n");
2387                 return E_FAIL;
2388             }
2389
2390             /* disable top XML declaration */
2391             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2392                               handle, NULL, XML_SAVE_NO_DECL);
2393             if (!ctx)
2394             {
2395                 CloseHandle(handle);
2396                 return E_FAIL;
2397             }
2398         }
2399         break;
2400
2401     default:
2402         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2403         return S_FALSE;
2404     }
2405
2406     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2407     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2408     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2409
2410     /* will release resources through close callback */
2411     xmlSaveClose(ctx);
2412
2413     return ret;
2414 }
2415
2416 static HRESULT WINAPI domdoc_get_validateOnParse(
2417     IXMLDOMDocument3 *iface,
2418     VARIANT_BOOL* isValidating )
2419 {
2420     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2421     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2422     *isValidating = This->validating;
2423     return S_OK;
2424 }
2425
2426
2427 static HRESULT WINAPI domdoc_put_validateOnParse(
2428     IXMLDOMDocument3 *iface,
2429     VARIANT_BOOL isValidating )
2430 {
2431     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2432     TRACE("(%p)->(%d)\n", This, isValidating);
2433     This->validating = isValidating;
2434     return S_OK;
2435 }
2436
2437
2438 static HRESULT WINAPI domdoc_get_resolveExternals(
2439     IXMLDOMDocument3 *iface,
2440     VARIANT_BOOL* isResolving )
2441 {
2442     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2443     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2444     *isResolving = This->resolving;
2445     return S_OK;
2446 }
2447
2448
2449 static HRESULT WINAPI domdoc_put_resolveExternals(
2450     IXMLDOMDocument3 *iface,
2451     VARIANT_BOOL isResolving )
2452 {
2453     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2454     TRACE("(%p)->(%d)\n", This, isResolving);
2455     This->resolving = isResolving;
2456     return S_OK;
2457 }
2458
2459
2460 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2461     IXMLDOMDocument3 *iface,
2462     VARIANT_BOOL* isPreserving )
2463 {
2464     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2465     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2466     *isPreserving = This->properties->preserving;
2467     return S_OK;
2468 }
2469
2470
2471 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2472     IXMLDOMDocument3 *iface,
2473     VARIANT_BOOL isPreserving )
2474 {
2475     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2476     TRACE("(%p)->(%d)\n", This, isPreserving);
2477     This->properties->preserving = isPreserving;
2478     return S_OK;
2479 }
2480
2481
2482 static HRESULT WINAPI domdoc_put_onreadystatechange(
2483     IXMLDOMDocument3 *iface,
2484     VARIANT event )
2485 {
2486     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2487
2488     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2489     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2490 }
2491
2492
2493 static HRESULT WINAPI domdoc_put_onDataAvailable(
2494     IXMLDOMDocument3 *iface,
2495     VARIANT onDataAvailableSink )
2496 {
2497     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2498     FIXME("%p\n", This);
2499     return E_NOTIMPL;
2500 }
2501
2502 static HRESULT WINAPI domdoc_put_onTransformNode(
2503     IXMLDOMDocument3 *iface,
2504     VARIANT onTransformNodeSink )
2505 {
2506     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2507     FIXME("%p\n", This);
2508     return E_NOTIMPL;
2509 }
2510
2511 static HRESULT WINAPI domdoc_get_namespaces(
2512     IXMLDOMDocument3* iface,
2513     IXMLDOMSchemaCollection** collection )
2514 {
2515     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2516     FIXME("(%p)->(%p): stub\n", This, collection);
2517
2518     if (!collection) return E_POINTER;
2519
2520     return E_NOTIMPL;
2521 }
2522
2523 static HRESULT WINAPI domdoc_get_schemas(
2524     IXMLDOMDocument3* iface,
2525     VARIANT* var1 )
2526 {
2527     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2528     HRESULT hr = S_FALSE;
2529     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2530
2531     TRACE("(%p)->(%p)\n", This, var1);
2532
2533     VariantInit(var1); /* Test shows we don't call VariantClear here */
2534     V_VT(var1) = VT_NULL;
2535
2536     if(cur_schema)
2537     {
2538         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2539         if(SUCCEEDED(hr))
2540             V_VT(var1) = VT_DISPATCH;
2541     }
2542     return hr;
2543 }
2544
2545 static HRESULT WINAPI domdoc_putref_schemas(
2546     IXMLDOMDocument3* iface,
2547     VARIANT var1)
2548 {
2549     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2550     HRESULT hr = E_FAIL;
2551     IXMLDOMSchemaCollection2* new_schema = NULL;
2552
2553     FIXME("(%p): semi-stub\n", This);
2554     switch(V_VT(&var1))
2555     {
2556     case VT_UNKNOWN:
2557         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2558         break;
2559
2560     case VT_DISPATCH:
2561         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2562         break;
2563
2564     case VT_NULL:
2565     case VT_EMPTY:
2566         hr = S_OK;
2567         break;
2568
2569     default:
2570         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2571     }
2572
2573     if(SUCCEEDED(hr))
2574     {
2575         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2576         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2577     }
2578
2579     return hr;
2580 }
2581
2582 static inline BOOL is_wellformed(xmlDocPtr doc)
2583 {
2584 #ifdef HAVE_XMLDOC_PROPERTIES
2585     return doc->properties & XML_DOC_WELLFORMED;
2586 #else
2587     /* Not a full check, but catches the worst violations */
2588     xmlNodePtr child;
2589     int root = 0;
2590
2591     for (child = doc->children; child != NULL; child = child->next)
2592     {
2593         switch (child->type)
2594         {
2595         case XML_ELEMENT_NODE:
2596             if (++root > 1)
2597                 return FALSE;
2598             break;
2599         case XML_TEXT_NODE:
2600         case XML_CDATA_SECTION_NODE:
2601             return FALSE;
2602             break;
2603         default:
2604             break;
2605         }
2606     }
2607
2608     return root == 1;
2609 #endif
2610 }
2611
2612 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2613 {
2614     va_list ap;
2615     va_start(ap, msg);
2616     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2617     va_end(ap);
2618 }
2619
2620 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2621 {
2622     va_list ap;
2623     va_start(ap, msg);
2624     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2625     va_end(ap);
2626 }
2627
2628 static HRESULT WINAPI domdoc_validateNode(
2629     IXMLDOMDocument3* iface,
2630     IXMLDOMNode* node,
2631     IXMLDOMParseError** err)
2632 {
2633     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2634     LONG state, err_code = 0;
2635     HRESULT hr = S_OK;
2636     int validated = 0;
2637
2638     TRACE("(%p)->(%p, %p)\n", This, node, err);
2639     domdoc_get_readyState(iface, &state);
2640     if (state != READYSTATE_COMPLETE)
2641     {
2642         if (err)
2643            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2644         return E_PENDING;
2645     }
2646
2647     if (!node)
2648     {
2649         if (err)
2650             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2651         return E_POINTER;
2652     }
2653
2654     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2655     {
2656         if (err)
2657             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2658         return E_FAIL;
2659     }
2660
2661     if (!is_wellformed(get_doc(This)))
2662     {
2663         ERR("doc not well-formed\n");
2664         if (err)
2665             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2666         return S_FALSE;
2667     }
2668
2669     /* DTD validation */
2670     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2671     {
2672         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2673         vctx->error = validate_error;
2674         vctx->warning = validate_warning;
2675         ++validated;
2676
2677         if (!((node == (IXMLDOMNode*)iface)?
2678               xmlValidateDocument(vctx, get_doc(This)) :
2679               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2680         {
2681             /* TODO: get a real error code here */
2682             TRACE("DTD validation failed\n");
2683             err_code = E_XML_INVALID;
2684             hr = S_FALSE;
2685         }
2686         xmlFreeValidCtxt(vctx);
2687     }
2688
2689     /* Schema validation */
2690     if (hr == S_OK && This->properties->schemaCache != NULL)
2691     {
2692
2693         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2694         if (SUCCEEDED(hr))
2695         {
2696             ++validated;
2697             /* TODO: get a real error code here */
2698             if (hr == S_OK)
2699             {
2700                 TRACE("schema validation succeeded\n");
2701             }
2702             else
2703             {
2704                 ERR("schema validation failed\n");
2705                 err_code = E_XML_INVALID;
2706             }
2707         }
2708         else
2709         {
2710             /* not really OK, just didn't find a schema for the ns */
2711             hr = S_OK;
2712         }
2713     }
2714
2715     if (!validated)
2716     {
2717         ERR("no DTD or schema found\n");
2718         err_code = E_XML_NODTD;
2719         hr = S_FALSE;
2720     }
2721
2722     if (err)
2723         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2724
2725     return hr;
2726 }
2727
2728 static HRESULT WINAPI domdoc_validate(
2729     IXMLDOMDocument3* iface,
2730     IXMLDOMParseError** err)
2731 {
2732     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2733     TRACE("(%p)->(%p)\n", This, err);
2734     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2735 }
2736
2737 static HRESULT WINAPI domdoc_setProperty(
2738     IXMLDOMDocument3* iface,
2739     BSTR p,
2740     VARIANT var)
2741 {
2742     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2743
2744     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2745
2746     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2747     {
2748         VARIANT varStr;
2749         HRESULT hr;
2750         BSTR bstr;
2751
2752         V_VT(&varStr) = VT_EMPTY;
2753         if (V_VT(&var) != VT_BSTR)
2754         {
2755             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2756                 return hr;
2757             bstr = V_BSTR(&varStr);
2758         }
2759         else
2760             bstr = V_BSTR(&var);
2761
2762         hr = S_OK;
2763         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2764             This->properties->XPath = TRUE;
2765         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2766             This->properties->XPath = FALSE;
2767         else
2768             hr = E_FAIL;
2769
2770         VariantClear(&varStr);
2771         return hr;
2772     }
2773     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2774     {
2775         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2776         struct list *pNsList;
2777         VARIANT varStr;
2778         HRESULT hr;
2779         BSTR bstr;
2780
2781         V_VT(&varStr) = VT_EMPTY;
2782         if (V_VT(&var) != VT_BSTR)
2783         {
2784             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2785                 return hr;
2786             bstr = V_BSTR(&varStr);
2787         }
2788         else
2789             bstr = V_BSTR(&var);
2790
2791         hr = S_OK;
2792
2793         pNsList = &(This->properties->selectNsList);
2794         clear_selectNsList(pNsList);
2795         heap_free(nsStr);
2796         nsStr = xmlchar_from_wchar(bstr);
2797
2798         TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2799
2800         This->properties->selectNsStr = nsStr;
2801         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2802         if (bstr && *bstr)
2803         {
2804             xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2805             select_ns_entry* ns_entry = NULL;
2806             xmlXPathContextPtr ctx;
2807
2808             ctx = xmlXPathNewContext(This->node.node->doc);
2809             pTokBegin = nsStr;
2810
2811             /* skip leading spaces */
2812             while (*pTokBegin == ' '  || *pTokBegin == '\n' ||
2813                    *pTokBegin == '\t' || *pTokBegin == '\r')
2814                 ++pTokBegin;
2815
2816             for (; *pTokBegin; pTokBegin = pTokEnd)
2817             {
2818                 if (ns_entry)
2819                     memset(ns_entry, 0, sizeof(select_ns_entry));
2820                 else
2821                     ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2822
2823                 while (*pTokBegin == ' ')
2824                     ++pTokBegin;
2825                 pTokEnd = pTokBegin;
2826                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2827                     ++pTokEnd;
2828
2829                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2830                 {
2831                     hr = E_FAIL;
2832                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2833                           debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2834                     continue;
2835                 }
2836
2837                 pTokBegin += 5;
2838                 if (*pTokBegin == '=')
2839                 {
2840                     /*valid for XSLPattern?*/
2841                     FIXME("Setting default xmlns not supported - skipping.\n");
2842                     continue;
2843                 }
2844                 else if (*pTokBegin == ':')
2845                 {
2846                     ns_entry->prefix = ++pTokBegin;
2847                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2848                         ;
2849
2850                     if (pTokInner == pTokEnd)
2851                     {
2852                         hr = E_FAIL;
2853                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2854                               debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2855                         continue;
2856                     }
2857
2858                     ns_entry->prefix_end = *pTokInner;
2859                     *pTokInner = 0;
2860                     ++pTokInner;
2861
2862                     if (pTokEnd-pTokInner > 1 &&
2863                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2864                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2865                     {
2866                         ns_entry->href = ++pTokInner;
2867                         ns_entry->href_end = *(pTokEnd-1);
2868                         *(pTokEnd-1) = 0;
2869                         list_add_tail(pNsList, &ns_entry->entry);
2870                         /*let libxml figure out if they're valid from here ;)*/
2871                         if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2872                         {
2873                             hr = E_FAIL;
2874                         }
2875                         ns_entry = NULL;
2876                         continue;
2877                     }
2878                     else
2879                     {
2880                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2881                               debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2882                         list_add_tail(pNsList, &ns_entry->entry);
2883
2884                         ns_entry = NULL;
2885                         hr = E_FAIL;
2886                         continue;
2887                     }
2888                 }
2889                 else
2890                 {
2891                     hr = E_FAIL;
2892                     continue;
2893                 }
2894             }
2895             heap_free(ns_entry);
2896             xmlXPathFreeContext(ctx);
2897         }
2898
2899         VariantClear(&varStr);
2900         return hr;
2901     }
2902     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2903              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2904              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2905     {
2906         /* Ignore */
2907         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2908         return S_OK;
2909     }
2910
2911     FIXME("Unknown property %s\n", debugstr_w(p));
2912     return E_FAIL;
2913 }
2914
2915 static HRESULT WINAPI domdoc_getProperty(
2916     IXMLDOMDocument3* iface,
2917     BSTR p,
2918     VARIANT* var)
2919 {
2920     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2921
2922     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2923
2924     if (!var)
2925         return E_INVALIDARG;
2926
2927     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2928     {
2929         V_VT(var) = VT_BSTR;
2930         V_BSTR(var) = This->properties->XPath ?
2931                       SysAllocString(PropValueXPathW) :
2932                       SysAllocString(PropValueXSLPatternW);
2933         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2934     }
2935     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2936     {
2937         int lenA, lenW;
2938         BSTR rebuiltStr, cur;
2939         const xmlChar *nsStr;
2940         struct list *pNsList;
2941         select_ns_entry* pNsEntry;
2942
2943         V_VT(var) = VT_BSTR;
2944         nsStr = This->properties->selectNsStr;
2945         pNsList = &This->properties->selectNsList;
2946         lenA = This->properties->selectNsStr_len;
2947         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2948         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2949         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2950         cur = rebuiltStr;
2951         /* this is fine because all of the chars that end tokens are ASCII*/
2952         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2953         {
2954             while (*cur != 0) ++cur;
2955             if (pNsEntry->prefix_end)
2956             {
2957                 *cur = pNsEntry->prefix_end;
2958                 while (*cur != 0) ++cur;
2959             }
2960
2961             if (pNsEntry->href_end)
2962             {
2963                 *cur = pNsEntry->href_end;
2964             }
2965         }
2966         V_BSTR(var) = SysAllocString(rebuiltStr);
2967         heap_free(rebuiltStr);
2968         return S_OK;
2969     }
2970
2971     FIXME("Unknown property %s\n", debugstr_w(p));
2972     return E_FAIL;
2973 }
2974
2975 static HRESULT WINAPI domdoc_importNode(
2976     IXMLDOMDocument3* iface,
2977     IXMLDOMNode* node,
2978     VARIANT_BOOL deep,
2979     IXMLDOMNode** clone)
2980 {
2981     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2982     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2983     return E_NOTIMPL;
2984 }
2985
2986 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2987 {
2988     domdoc_QueryInterface,
2989     domdoc_AddRef,
2990     domdoc_Release,
2991     domdoc_GetTypeInfoCount,
2992     domdoc_GetTypeInfo,
2993     domdoc_GetIDsOfNames,
2994     domdoc_Invoke,
2995     domdoc_get_nodeName,
2996     domdoc_get_nodeValue,
2997     domdoc_put_nodeValue,
2998     domdoc_get_nodeType,
2999     domdoc_get_parentNode,
3000     domdoc_get_childNodes,
3001     domdoc_get_firstChild,
3002     domdoc_get_lastChild,
3003     domdoc_get_previousSibling,
3004     domdoc_get_nextSibling,
3005     domdoc_get_attributes,
3006     domdoc_insertBefore,
3007     domdoc_replaceChild,
3008     domdoc_removeChild,
3009     domdoc_appendChild,
3010     domdoc_hasChildNodes,
3011     domdoc_get_ownerDocument,
3012     domdoc_cloneNode,
3013     domdoc_get_nodeTypeString,
3014     domdoc_get_text,
3015     domdoc_put_text,
3016     domdoc_get_specified,
3017     domdoc_get_definition,
3018     domdoc_get_nodeTypedValue,
3019     domdoc_put_nodeTypedValue,
3020     domdoc_get_dataType,
3021     domdoc_put_dataType,
3022     domdoc_get_xml,
3023     domdoc_transformNode,
3024     domdoc_selectNodes,
3025     domdoc_selectSingleNode,
3026     domdoc_get_parsed,
3027     domdoc_get_namespaceURI,
3028     domdoc_get_prefix,
3029     domdoc_get_baseName,
3030     domdoc_transformNodeToObject,
3031     domdoc_get_doctype,
3032     domdoc_get_implementation,
3033     domdoc_get_documentElement,
3034     domdoc_put_documentElement,
3035     domdoc_createElement,
3036     domdoc_createDocumentFragment,
3037     domdoc_createTextNode,
3038     domdoc_createComment,
3039     domdoc_createCDATASection,
3040     domdoc_createProcessingInstruction,
3041     domdoc_createAttribute,
3042     domdoc_createEntityReference,
3043     domdoc_getElementsByTagName,
3044     domdoc_createNode,
3045     domdoc_nodeFromID,
3046     domdoc_load,
3047     domdoc_get_readyState,
3048     domdoc_get_parseError,
3049     domdoc_get_url,
3050     domdoc_get_async,
3051     domdoc_put_async,
3052     domdoc_abort,
3053     domdoc_loadXML,
3054     domdoc_save,
3055     domdoc_get_validateOnParse,
3056     domdoc_put_validateOnParse,
3057     domdoc_get_resolveExternals,
3058     domdoc_put_resolveExternals,
3059     domdoc_get_preserveWhiteSpace,
3060     domdoc_put_preserveWhiteSpace,
3061     domdoc_put_onreadystatechange,
3062     domdoc_put_onDataAvailable,
3063     domdoc_put_onTransformNode,
3064     domdoc_get_namespaces,
3065     domdoc_get_schemas,
3066     domdoc_putref_schemas,
3067     domdoc_validate,
3068     domdoc_setProperty,
3069     domdoc_getProperty,
3070     domdoc_validateNode,
3071     domdoc_importNode
3072 };
3073
3074 /* IConnectionPointContainer */
3075 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3076                                                               REFIID riid, void **ppv)
3077 {
3078     domdoc *This = impl_from_IConnectionPointContainer(iface);
3079     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3080 }
3081
3082 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3083 {
3084     domdoc *This = impl_from_IConnectionPointContainer(iface);
3085     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3086 }
3087
3088 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3089 {
3090     domdoc *This = impl_from_IConnectionPointContainer(iface);
3091     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3092 }
3093
3094 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3095         IEnumConnectionPoints **ppEnum)
3096 {
3097     domdoc *This = impl_from_IConnectionPointContainer(iface);
3098     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3099     return E_NOTIMPL;
3100 }
3101
3102 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3103         REFIID riid, IConnectionPoint **cp)
3104 {
3105     domdoc *This = impl_from_IConnectionPointContainer(iface);
3106     ConnectionPoint *iter;
3107
3108     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3109
3110     *cp = NULL;
3111
3112     for(iter = This->cp_list; iter; iter = iter->next)
3113     {
3114         if (IsEqualGUID(iter->iid, riid))
3115             *cp = &iter->IConnectionPoint_iface;
3116     }
3117
3118     if (*cp)
3119     {
3120         IConnectionPoint_AddRef(*cp);
3121         return S_OK;
3122     }
3123
3124     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3125     return CONNECT_E_NOCONNECTION;
3126
3127 }
3128
3129 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3130 {
3131     ConnectionPointContainer_QueryInterface,
3132     ConnectionPointContainer_AddRef,
3133     ConnectionPointContainer_Release,
3134     ConnectionPointContainer_EnumConnectionPoints,
3135     ConnectionPointContainer_FindConnectionPoint
3136 };
3137
3138 /* IConnectionPoint */
3139 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3140                                                      REFIID riid, void **ppv)
3141 {
3142     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3143
3144     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3145
3146     *ppv = NULL;
3147
3148     if (IsEqualGUID(&IID_IUnknown, riid) ||
3149         IsEqualGUID(&IID_IConnectionPoint, riid))
3150     {
3151         *ppv = iface;
3152     }
3153
3154     if (*ppv)
3155     {
3156         IConnectionPoint_AddRef(iface);
3157         return S_OK;
3158     }
3159
3160     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3161     return E_NOINTERFACE;
3162 }
3163
3164 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3165 {
3166     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3167     return IConnectionPointContainer_AddRef(This->container);
3168 }
3169
3170 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3171 {
3172     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3173     return IConnectionPointContainer_Release(This->container);
3174 }
3175
3176 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3177 {
3178     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3179
3180     TRACE("(%p)->(%p)\n", This, iid);
3181
3182     if (!iid) return E_POINTER;
3183
3184     *iid = *This->iid;
3185     return S_OK;
3186 }
3187
3188 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3189         IConnectionPointContainer **container)
3190 {
3191     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3192
3193     TRACE("(%p)->(%p)\n", This, container);
3194
3195     if (!container) return E_POINTER;
3196
3197     *container = This->container;
3198     IConnectionPointContainer_AddRef(*container);
3199     return S_OK;
3200 }
3201
3202 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3203                                              DWORD *pdwCookie)
3204 {
3205     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3206     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3207     return E_NOTIMPL;
3208 }
3209
3210 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3211 {
3212     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3213
3214     TRACE("(%p)->(%d)\n", This, cookie);
3215
3216     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3217         return CONNECT_E_NOCONNECTION;
3218
3219     IUnknown_Release(This->sinks[cookie-1].unk);
3220     This->sinks[cookie-1].unk = NULL;
3221
3222     return S_OK;
3223 }
3224
3225 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3226                                                       IEnumConnections **ppEnum)
3227 {
3228     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3229     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3230     return E_NOTIMPL;
3231 }
3232
3233 static const IConnectionPointVtbl ConnectionPointVtbl =
3234 {
3235     ConnectionPoint_QueryInterface,
3236     ConnectionPoint_AddRef,
3237     ConnectionPoint_Release,
3238     ConnectionPoint_GetConnectionInterface,
3239     ConnectionPoint_GetConnectionPointContainer,
3240     ConnectionPoint_Advise,
3241     ConnectionPoint_Unadvise,
3242     ConnectionPoint_EnumConnections
3243 };
3244
3245 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3246 {
3247     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3248     cp->doc = doc;
3249     cp->iid = riid;
3250     cp->sinks = NULL;
3251     cp->sinks_size = 0;
3252
3253     cp->next = doc->cp_list;
3254     doc->cp_list = cp;
3255
3256     cp->container = &doc->IConnectionPointContainer_iface;
3257 }
3258
3259 /* domdoc implementation of IObjectWithSite */
3260 static HRESULT WINAPI
3261 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3262 {
3263     domdoc *This = impl_from_IObjectWithSite(iface);
3264     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3265 }
3266
3267 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3268 {
3269     domdoc *This = impl_from_IObjectWithSite(iface);
3270     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3271 }
3272
3273 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3274 {
3275     domdoc *This = impl_from_IObjectWithSite(iface);
3276     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3277 }
3278
3279 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3280 {
3281     domdoc *This = impl_from_IObjectWithSite(iface);
3282
3283     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3284
3285     if ( !This->site )
3286         return E_FAIL;
3287
3288     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3289 }
3290
3291 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3292 {
3293     domdoc *This = impl_from_IObjectWithSite(iface);
3294
3295     TRACE("(%p)->(%p)\n", iface, punk);
3296
3297     if(!punk)
3298     {
3299         if(This->site)
3300         {
3301             IUnknown_Release( This->site );
3302             This->site = NULL;
3303         }
3304
3305         return S_OK;
3306     }
3307
3308     IUnknown_AddRef( punk );
3309
3310     if(This->site)
3311         IUnknown_Release( This->site );
3312
3313     This->site = punk;
3314
3315     return S_OK;
3316 }
3317
3318 static const IObjectWithSiteVtbl domdocObjectSite =
3319 {
3320     domdoc_ObjectWithSite_QueryInterface,
3321     domdoc_ObjectWithSite_AddRef,
3322     domdoc_ObjectWithSite_Release,
3323     domdoc_ObjectWithSite_SetSite,
3324     domdoc_ObjectWithSite_GetSite
3325 };
3326
3327 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3328 {
3329     domdoc *This = impl_from_IObjectSafety(iface);
3330     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3331 }
3332
3333 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3334 {
3335     domdoc *This = impl_from_IObjectSafety(iface);
3336     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3337 }
3338
3339 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3340 {
3341     domdoc *This = impl_from_IObjectSafety(iface);
3342     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3343 }
3344
3345 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3346
3347 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3348         DWORD *supported, DWORD *enabled)
3349 {
3350     domdoc *This = impl_from_IObjectSafety(iface);
3351
3352     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3353
3354     if(!supported || !enabled) return E_POINTER;
3355
3356     *supported = SAFETY_SUPPORTED_OPTIONS;
3357     *enabled = This->safeopt;
3358
3359     return S_OK;
3360 }
3361
3362 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3363         DWORD mask, DWORD enabled)
3364 {
3365     domdoc *This = impl_from_IObjectSafety(iface);
3366     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3367
3368     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3369         return E_FAIL;
3370
3371     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3372
3373     return S_OK;
3374 }
3375
3376 #undef SAFETY_SUPPORTED_OPTIONS
3377
3378 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3379     domdoc_Safety_QueryInterface,
3380     domdoc_Safety_AddRef,
3381     domdoc_Safety_Release,
3382     domdoc_Safety_GetInterfaceSafetyOptions,
3383     domdoc_Safety_SetInterfaceSafetyOptions
3384 };
3385
3386 static const tid_t domdoc_iface_tids[] = {
3387     IXMLDOMDocument3_tid,
3388     0
3389 };
3390
3391 static dispex_static_data_t domdoc_dispex = {
3392     NULL,
3393     IXMLDOMDocument3_tid,
3394     NULL,
3395     domdoc_iface_tids
3396 };
3397
3398 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3399 {
3400     domdoc *doc;
3401
3402     doc = heap_alloc( sizeof (*doc) );
3403     if( !doc )
3404         return E_OUTOFMEMORY;
3405
3406     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3407     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3408     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3409     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3410     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3411     doc->ref = 1;
3412     doc->async = VARIANT_TRUE;
3413     doc->validating = 0;
3414     doc->resolving = 0;
3415     doc->properties = properties_from_xmlDocPtr(xmldoc);
3416     doc->error = S_OK;
3417     doc->stream = NULL;
3418     doc->site = NULL;
3419     doc->safeopt = 0;
3420     doc->bsc = NULL;
3421     doc->cp_list = NULL;
3422     memset(doc->events, 0, sizeof(doc->events));
3423
3424     /* events connection points */
3425     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3426     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3427     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3428
3429     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3430             &domdoc_dispex);
3431
3432     *document = &doc->IXMLDOMDocument3_iface;
3433
3434     TRACE("returning iface %p\n", *document);
3435     return S_OK;
3436 }
3437
3438 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3439 {
3440     xmlDocPtr xmldoc;
3441     HRESULT hr;
3442
3443     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3444
3445     xmldoc = xmlNewDoc(NULL);
3446     if(!xmldoc)
3447         return E_OUTOFMEMORY;
3448
3449     xmldoc_init(xmldoc, version);
3450
3451     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3452     if(FAILED(hr))
3453     {
3454         free_properties(properties_from_xmlDocPtr(xmldoc));
3455         heap_free(xmldoc->_private);
3456         xmlFreeDoc(xmldoc);
3457         return hr;
3458     }
3459
3460     return hr;
3461 }
3462
3463 IUnknown* create_domdoc( xmlNodePtr document )
3464 {
3465     void* pObj = NULL;
3466     HRESULT hr;
3467
3468     TRACE("(%p)\n", document);
3469
3470     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3471     if (FAILED(hr))
3472         return NULL;
3473
3474     return pObj;
3475 }
3476
3477 #else
3478
3479 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3480 {
3481     MESSAGE("This program tried to use a DOMDocument object, but\n"
3482             "libxml2 support was not present at compile time.\n");
3483     return E_NOTIMPL;
3484 }
3485
3486 #endif