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