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