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