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