msxml3: Added partial XMLView IPersistMoniker_Load implementation.
[wine] / dlls / msxml3 / domdoc.c
1 /*
2  *    DOM Document implementation
3  *
4  * Copyright 2005 Mike McCormack
5  * Copyright 2010-2011 Adam Martinson for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23 #define NONAMELESSUNION
24
25 #include "config.h"
26
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
37
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
50
51 #include "wine/debug.h"
52 #include "wine/list.h"
53
54 #include "msxml_private.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
57
58 #ifdef HAVE_LIBXML2
59
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT     1
62 #define XML_SAVE_NO_DECL    2
63 #define XML_SAVE_NO_EMPTY   4
64 #define XML_SAVE_NO_XHTML   8
65 #define XML_SAVE_XHTML     16
66 #define XML_SAVE_AS_XML    32
67 #define XML_SAVE_AS_HTML   64
68
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
76
77 /* Anything that passes the test_get_ownerDocument()
78  * tests can go here (data shared between all instances).
79  * We need to preserve this when reloading a document,
80  * and also need access to it from the libxml backend. */
81 typedef struct {
82     MSXML_VERSION version;
83     VARIANT_BOOL preserving;
84     IXMLDOMSchemaCollection2* schemaCache;
85     struct list selectNsList;
86     xmlChar const* selectNsStr;
87     LONG selectNsStr_len;
88     BOOL XPath;
89 } domdoc_properties;
90
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
93
94 struct ConnectionPoint
95 {
96     IConnectionPoint IConnectionPoint_iface;
97     const IID *iid;
98
99     ConnectionPoint *next;
100     IConnectionPointContainer *container;
101     domdoc *doc;
102
103     union
104     {
105         IUnknown *unk;
106         IDispatch *disp;
107         IPropertyNotifySink *propnotif;
108     } *sinks;
109     DWORD sinks_size;
110 };
111
112 typedef enum {
113     EVENTID_READYSTATECHANGE = 0,
114     EVENTID_DATAAVAILABLE,
115     EVENTID_TRANSFORMNODE,
116     EVENTID_LAST
117 } eventid_t;
118
119 struct domdoc
120 {
121     xmlnode node;
122     IXMLDOMDocument3          IXMLDOMDocument3_iface;
123     IPersistStreamInit        IPersistStreamInit_iface;
124     IObjectWithSite           IObjectWithSite_iface;
125     IObjectSafety             IObjectSafety_iface;
126     IConnectionPointContainer IConnectionPointContainer_iface;
127     LONG ref;
128     VARIANT_BOOL async;
129     VARIANT_BOOL validating;
130     VARIANT_BOOL resolving;
131     domdoc_properties* properties;
132     bsc_t *bsc;
133     HRESULT error;
134
135     /* IPersistStream */
136     IStream *stream;
137
138     /* IObjectWithSite*/
139     IUnknown *site;
140
141     /* IObjectSafety */
142     DWORD safeopt;
143
144     /* connection list */
145     ConnectionPoint *cp_list;
146     ConnectionPoint cp_domdocevents;
147     ConnectionPoint cp_propnotif;
148     ConnectionPoint cp_dispatch;
149
150     /* events */
151     IDispatch *events[EVENTID_LAST];
152
153     IXMLDOMSchemaCollection2 *namespaces;
154 };
155
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
157 {
158     IDispatch *disp;
159
160     switch (V_VT(v))
161     {
162     case VT_UNKNOWN:
163         if (V_UNKNOWN(v))
164             IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165         else
166             disp = NULL;
167         break;
168     case VT_DISPATCH:
169         disp = V_DISPATCH(v);
170         if (disp) IDispatch_AddRef(disp);
171         break;
172     default:
173         return DISP_E_TYPEMISMATCH;
174     }
175
176     if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177     doc->events[eid] = disp;
178
179     return S_OK;
180 }
181
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
183 {
184     return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 }
186
187 /*
188   In native windows, the whole lifetime management of XMLDOMNodes is
189   managed automatically using reference counts. Wine emulates that by
190   maintaining a reference count to the document that is increased for
191   each IXMLDOMNode pointer passed out for this document. If all these
192   pointers are gone, the document is unreachable and gets freed, that
193   is, all nodes in the tree of the document get freed.
194
195   You are able to create nodes that are associated to a document (in
196   fact, in msxml's XMLDOM model, all nodes are associated to a document),
197   but not in the tree of that document, for example using the createFoo
198   functions from IXMLDOMDocument. These nodes do not get cleaned up
199   by libxml, so we have to do it ourselves.
200
201   To catch these nodes, a list of "orphan nodes" is introduced.
202   It contains pointers to all roots of node trees that are
203   associated with the document without being part of the document
204   tree. All nodes with parent==NULL (except for the document root nodes)
205   should be in the orphan node list of their document. All orphan nodes
206   get freed together with the document itself.
207  */
208
209 typedef struct _xmldoc_priv {
210     LONG refs;
211     struct list orphans;
212     domdoc_properties* properties;
213 } xmldoc_priv;
214
215 typedef struct _orphan_entry {
216     struct list entry;
217     xmlNode * node;
218 } orphan_entry;
219
220 typedef struct _select_ns_entry {
221     struct list entry;
222     xmlChar const* prefix;
223     xmlChar prefix_end;
224     xmlChar const* href;
225     xmlChar href_end;
226 } select_ns_entry;
227
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
229 {
230     return doc->_private;
231 }
232
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
234 {
235     return priv_from_xmlDocPtr(doc)->properties;
236 }
237
238 BOOL is_xpathmode(const xmlDocPtr doc)
239 {
240     return properties_from_xmlDocPtr(doc)->XPath;
241 }
242
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
244 {
245     properties_from_xmlDocPtr(doc)->XPath = xpath;
246 }
247
248 int registerNamespaces(xmlXPathContextPtr ctxt)
249 {
250     int n = 0;
251     const select_ns_entry* ns = NULL;
252     const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
253
254     TRACE("(%p)\n", ctxt);
255
256     LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
257     {
258         xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259         ++n;
260     }
261
262     return n;
263 }
264
265 static inline void clear_selectNsList(struct list* pNsList)
266 {
267     select_ns_entry *ns, *ns2;
268     LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
269     {
270         heap_free( ns );
271     }
272     list_init(pNsList);
273 }
274
275 static xmldoc_priv * create_priv(void)
276 {
277     xmldoc_priv *priv;
278     priv = heap_alloc( sizeof (*priv) );
279
280     if (priv)
281     {
282         priv->refs = 0;
283         list_init( &priv->orphans );
284         priv->properties = NULL;
285     }
286
287     return priv;
288 }
289
290 static domdoc_properties *create_properties(MSXML_VERSION version)
291 {
292     domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
293
294     list_init(&properties->selectNsList);
295     properties->preserving = VARIANT_FALSE;
296     properties->schemaCache = NULL;
297     properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298     properties->selectNsStr_len = 0;
299
300     /* properties that are dependent on object versions */
301     properties->version = version;
302     properties->XPath = (version == MSXML4 || version == MSXML6);
303
304     return properties;
305 }
306
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
308 {
309     domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310     select_ns_entry const* ns = NULL;
311     select_ns_entry* new_ns = NULL;
312     int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313     ptrdiff_t offset;
314
315     if (pcopy)
316     {
317         pcopy->version = properties->version;
318         pcopy->preserving = properties->preserving;
319         pcopy->schemaCache = properties->schemaCache;
320         if (pcopy->schemaCache)
321             IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322         pcopy->XPath = properties->XPath;
323         pcopy->selectNsStr_len = properties->selectNsStr_len;
324         list_init( &pcopy->selectNsList );
325         pcopy->selectNsStr = heap_alloc(len);
326         memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327         offset = pcopy->selectNsStr - properties->selectNsStr;
328
329         LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
330         {
331             new_ns = heap_alloc(sizeof(select_ns_entry));
332             memcpy(new_ns, ns, sizeof(select_ns_entry));
333             new_ns->href += offset;
334             new_ns->prefix += offset;
335             list_add_tail(&pcopy->selectNsList, &new_ns->entry);
336         }
337
338     }
339
340     return pcopy;
341 }
342
343 static void free_properties(domdoc_properties* properties)
344 {
345     if (properties)
346     {
347         if (properties->schemaCache)
348             IXMLDOMSchemaCollection2_Release(properties->schemaCache);
349         clear_selectNsList(&properties->selectNsList);
350         heap_free((xmlChar*)properties->selectNsStr);
351         heap_free(properties);
352     }
353 }
354
355 static void release_namespaces(domdoc *This)
356 {
357     if (This->namespaces)
358     {
359         IXMLDOMSchemaCollection2_Release(This->namespaces);
360         This->namespaces = NULL;
361     }
362 }
363
364 /* links a "<?xml" node as a first child */
365 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
366 {
367     assert(doc != NULL);
368     if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
369 }
370
371 /* unlinks a first "<?xml" child if it was created */
372 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
373 {
374     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 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2000 {
2001     bsc_t *bsc;
2002     HRESULT hr;
2003
2004     hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2005     if(FAILED(hr))
2006         return hr;
2007
2008     if(This->bsc) {
2009         hr = detach_bsc(This->bsc);
2010         if(FAILED(hr))
2011             return hr;
2012     }
2013
2014     This->bsc = bsc;
2015     return S_OK;
2016 }
2017
2018 static HRESULT WINAPI domdoc_load(
2019     IXMLDOMDocument3 *iface,
2020     VARIANT source,
2021     VARIANT_BOOL* isSuccessful )
2022 {
2023     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2024     LPWSTR filename = NULL;
2025     HRESULT hr = S_FALSE;
2026     IXMLDOMDocument3 *pNewDoc = NULL;
2027     IStream *pStream = NULL;
2028     xmlDocPtr xmldoc;
2029
2030     TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2031
2032     if (!isSuccessful)
2033         return E_POINTER;
2034     *isSuccessful = VARIANT_FALSE;
2035
2036     assert( &This->node );
2037
2038     switch( V_VT(&source) )
2039     {
2040     case VT_BSTR:
2041         filename = V_BSTR(&source);
2042         break;
2043     case VT_BSTR|VT_BYREF:
2044         if (!V_BSTRREF(&source)) return E_INVALIDARG;
2045         filename = *V_BSTRREF(&source);
2046         break;
2047     case VT_ARRAY|VT_UI1:
2048         {
2049             SAFEARRAY *psa = V_ARRAY(&source);
2050             char *str;
2051             LONG len;
2052             UINT dim = SafeArrayGetDim(psa);
2053
2054             switch (dim)
2055             {
2056             case 0:
2057                 ERR("SAFEARRAY == NULL\n");
2058                 hr = This->error = E_INVALIDARG;
2059                 break;
2060             case 1:
2061                 /* Only takes UTF-8 strings.
2062                  * NOT NULL-terminated. */
2063                 SafeArrayAccessData(psa, (void**)&str);
2064                 SafeArrayGetUBound(psa, 1, &len);
2065
2066                 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2067                 {
2068                     hr = This->error = S_OK;
2069                     *isSuccessful = VARIANT_TRUE;
2070                     TRACE("parsed document %p\n", xmldoc);
2071                 }
2072                 else
2073                 {
2074                     This->error = E_FAIL;
2075                     TRACE("failed to parse document\n");
2076                 }
2077
2078                 SafeArrayUnaccessData(psa);
2079
2080                 if(xmldoc)
2081                 {
2082                     xmldoc->_private = create_priv();
2083                     return attach_xmldoc(This, xmldoc);
2084                 }
2085                 break;
2086             default:
2087                 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2088                 hr = This->error = E_NOTIMPL;
2089             }
2090         }
2091         break;
2092     case VT_UNKNOWN:
2093         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2094         if(hr == S_OK)
2095         {
2096             if(pNewDoc)
2097             {
2098                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2099
2100                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2101                 xmldoc->_private = create_priv();
2102                 hr = attach_xmldoc(This, xmldoc);
2103
2104                 if(SUCCEEDED(hr))
2105                     *isSuccessful = VARIANT_TRUE;
2106
2107                 return hr;
2108             }
2109         }
2110         hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2111         if(hr == S_OK)
2112         {
2113             IPersistStream *pDocStream;
2114             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2115             if(hr == S_OK)
2116             {
2117                 hr = IPersistStream_Load(pDocStream, pStream);
2118                 IStream_Release(pStream);
2119                 if(hr == S_OK)
2120                 {
2121                     *isSuccessful = VARIANT_TRUE;
2122
2123                     TRACE("Using IStream to load Document\n");
2124                     return S_OK;
2125                 }
2126                 else
2127                 {
2128                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2129                 }
2130             }
2131             else
2132             {
2133                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2134             }
2135         }
2136         else
2137         {
2138             /* ISequentialStream */
2139             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2140         }
2141         break;
2142      default:
2143             FIXME("VT type not supported (%d)\n", V_VT(&source));
2144     }
2145
2146     if ( filename )
2147     {
2148         IMoniker *mon;
2149
2150         hr = create_moniker_from_url( filename, &mon);
2151         if ( SUCCEEDED(hr) )
2152         {
2153             hr = domdoc_load_moniker( This, mon );
2154             IMoniker_Release(mon);
2155         }
2156
2157         if ( FAILED(hr) )
2158             This->error = E_FAIL;
2159         else
2160         {
2161             hr = This->error = S_OK;
2162             *isSuccessful = VARIANT_TRUE;
2163         }
2164     }
2165
2166     if(!filename || FAILED(hr)) {
2167         xmldoc = xmlNewDoc(NULL);
2168         xmldoc->_private = create_priv();
2169         hr = attach_xmldoc(This, xmldoc);
2170         if(SUCCEEDED(hr))
2171             hr = S_FALSE;
2172     }
2173
2174     TRACE("ret (%d)\n", hr);
2175
2176     return hr;
2177 }
2178
2179
2180 static HRESULT WINAPI domdoc_get_readyState(
2181     IXMLDOMDocument3 *iface,
2182     LONG *value )
2183 {
2184     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2185     FIXME("stub! (%p)->(%p)\n", This, value);
2186
2187     if (!value)
2188         return E_INVALIDARG;
2189
2190     *value = READYSTATE_COMPLETE;
2191     return S_OK;
2192 }
2193
2194
2195 static HRESULT WINAPI domdoc_get_parseError(
2196     IXMLDOMDocument3 *iface,
2197     IXMLDOMParseError** errorObj )
2198 {
2199     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2200     static const WCHAR err[] = {'e','r','r','o','r',0};
2201     BSTR error_string = NULL;
2202
2203     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2204
2205     if(This->error)
2206         error_string = SysAllocString(err);
2207
2208     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2209     if(!*errorObj) return E_OUTOFMEMORY;
2210     return S_OK;
2211 }
2212
2213
2214 static HRESULT WINAPI domdoc_get_url(
2215     IXMLDOMDocument3 *iface,
2216     BSTR* urlString )
2217 {
2218     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2219     FIXME("(%p)->(%p)\n", This, urlString);
2220     return E_NOTIMPL;
2221 }
2222
2223
2224 static HRESULT WINAPI domdoc_get_async(
2225     IXMLDOMDocument3 *iface,
2226     VARIANT_BOOL* isAsync )
2227 {
2228     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2229
2230     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2231     *isAsync = This->async;
2232     return S_OK;
2233 }
2234
2235
2236 static HRESULT WINAPI domdoc_put_async(
2237     IXMLDOMDocument3 *iface,
2238     VARIANT_BOOL isAsync )
2239 {
2240     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2241
2242     TRACE("(%p)->(%d)\n", This, isAsync);
2243     This->async = isAsync;
2244     return S_OK;
2245 }
2246
2247
2248 static HRESULT WINAPI domdoc_abort(
2249     IXMLDOMDocument3 *iface )
2250 {
2251     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2252     FIXME("%p\n", This);
2253     return E_NOTIMPL;
2254 }
2255
2256 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2257 static HRESULT WINAPI domdoc_loadXML(
2258     IXMLDOMDocument3 *iface,
2259     BSTR data,
2260     VARIANT_BOOL* isSuccessful )
2261 {
2262     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2263     xmlDocPtr xmldoc = NULL;
2264     HRESULT hr = S_FALSE, hr2;
2265
2266     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2267
2268     assert ( &This->node );
2269
2270     if ( isSuccessful )
2271     {
2272         *isSuccessful = VARIANT_FALSE;
2273
2274         if (data)
2275         {
2276             WCHAR *ptr = data;
2277
2278             /* skip leading spaces if needed */
2279             if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2280                  while (*ptr)
2281                     if (isspaceW(*ptr)) ptr++; else break;
2282
2283             xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2284             if ( !xmldoc )
2285             {
2286                 This->error = E_FAIL;
2287                 TRACE("failed to parse document\n");
2288             }
2289             else
2290             {
2291                 hr = This->error = S_OK;
2292                 *isSuccessful = VARIANT_TRUE;
2293                 TRACE("parsed document %p\n", xmldoc);
2294             }
2295         }
2296     }
2297
2298     if(!xmldoc)
2299         xmldoc = xmlNewDoc(NULL);
2300     xmldoc->_private = create_priv();
2301     hr2 = attach_xmldoc(This, xmldoc);
2302     if( FAILED(hr2) )
2303         hr = hr2;
2304
2305     return hr;
2306 }
2307
2308 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2309 {
2310     DWORD written = -1;
2311
2312     if(!WriteFile(ctx, buffer, len, &written, NULL))
2313     {
2314         WARN("write error\n");
2315         return -1;
2316     }
2317     else
2318         return written;
2319 }
2320
2321 static int XMLCALL domdoc_save_closecallback(void *ctx)
2322 {
2323     return CloseHandle(ctx) ? 0 : -1;
2324 }
2325
2326 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2327 {
2328     ULONG written = 0;
2329     HRESULT hr;
2330
2331     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2332     if (hr != S_OK)
2333     {
2334         WARN("stream write error: 0x%08x\n", hr);
2335         return -1;
2336     }
2337     else
2338         return written;
2339 }
2340
2341 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2342 {
2343     IStream_Release((IStream*)ctx);
2344     return 0;
2345 }
2346
2347 static HRESULT WINAPI domdoc_save(
2348     IXMLDOMDocument3 *iface,
2349     VARIANT destination )
2350 {
2351     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2352     xmlSaveCtxtPtr ctx = NULL;
2353     xmlNodePtr xmldecl;
2354     HRESULT ret = S_OK;
2355
2356     TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2357
2358     switch (V_VT(&destination))
2359     {
2360     case VT_UNKNOWN:
2361         {
2362             IUnknown *pUnk = V_UNKNOWN(&destination);
2363             IXMLDOMDocument3 *document;
2364             IStream *stream;
2365
2366             ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2367             if(ret == S_OK)
2368             {
2369                 VARIANT_BOOL success;
2370                 BSTR xml;
2371
2372                 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2373                 if(ret == S_OK)
2374                 {
2375                     ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2376                     SysFreeString(xml);
2377                 }
2378
2379                 IXMLDOMDocument3_Release(document);
2380                 return ret;
2381             }
2382
2383             ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2384             if(ret == S_OK)
2385             {
2386                 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2387                     domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2388
2389                 if(!ctx)
2390                 {
2391                     IStream_Release(stream);
2392                     return E_FAIL;
2393                 }
2394             }
2395         }
2396         break;
2397
2398     case VT_BSTR:
2399     case VT_BSTR | VT_BYREF:
2400         {
2401             /* save with file path */
2402             HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2403                                          GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2404             if( handle == INVALID_HANDLE_VALUE )
2405             {
2406                 WARN("failed to create file\n");
2407                 return E_FAIL;
2408             }
2409
2410             /* disable top XML declaration */
2411             ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2412                               handle, NULL, XML_SAVE_NO_DECL);
2413             if (!ctx)
2414             {
2415                 CloseHandle(handle);
2416                 return E_FAIL;
2417             }
2418         }
2419         break;
2420
2421     default:
2422         FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2423         return S_FALSE;
2424     }
2425
2426     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2427     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2428     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2429
2430     /* will release resources through close callback */
2431     xmlSaveClose(ctx);
2432
2433     return ret;
2434 }
2435
2436 static HRESULT WINAPI domdoc_get_validateOnParse(
2437     IXMLDOMDocument3 *iface,
2438     VARIANT_BOOL* isValidating )
2439 {
2440     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2441     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2442     *isValidating = This->validating;
2443     return S_OK;
2444 }
2445
2446
2447 static HRESULT WINAPI domdoc_put_validateOnParse(
2448     IXMLDOMDocument3 *iface,
2449     VARIANT_BOOL isValidating )
2450 {
2451     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2452     TRACE("(%p)->(%d)\n", This, isValidating);
2453     This->validating = isValidating;
2454     return S_OK;
2455 }
2456
2457
2458 static HRESULT WINAPI domdoc_get_resolveExternals(
2459     IXMLDOMDocument3 *iface,
2460     VARIANT_BOOL* isResolving )
2461 {
2462     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2463     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2464     *isResolving = This->resolving;
2465     return S_OK;
2466 }
2467
2468
2469 static HRESULT WINAPI domdoc_put_resolveExternals(
2470     IXMLDOMDocument3 *iface,
2471     VARIANT_BOOL isResolving )
2472 {
2473     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2474     TRACE("(%p)->(%d)\n", This, isResolving);
2475     This->resolving = isResolving;
2476     return S_OK;
2477 }
2478
2479
2480 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2481     IXMLDOMDocument3 *iface,
2482     VARIANT_BOOL* isPreserving )
2483 {
2484     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2485     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2486     *isPreserving = This->properties->preserving;
2487     return S_OK;
2488 }
2489
2490
2491 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2492     IXMLDOMDocument3 *iface,
2493     VARIANT_BOOL isPreserving )
2494 {
2495     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496     TRACE("(%p)->(%d)\n", This, isPreserving);
2497     This->properties->preserving = isPreserving;
2498     return S_OK;
2499 }
2500
2501
2502 static HRESULT WINAPI domdoc_put_onreadystatechange(
2503     IXMLDOMDocument3 *iface,
2504     VARIANT event )
2505 {
2506     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2507
2508     TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2509     return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2510 }
2511
2512
2513 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2514 {
2515     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2516     FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2517     return E_NOTIMPL;
2518 }
2519
2520 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2521 {
2522     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523     FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2524     return E_NOTIMPL;
2525 }
2526
2527 static HRESULT WINAPI domdoc_get_namespaces(
2528     IXMLDOMDocument3* iface,
2529     IXMLDOMSchemaCollection** collection )
2530 {
2531     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2532     HRESULT hr;
2533
2534     FIXME("(%p)->(%p): semi-stub\n", This, collection);
2535
2536     if (!collection) return E_POINTER;
2537
2538     if (!This->namespaces)
2539     {
2540         hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2541         if (hr != S_OK) return hr;
2542
2543         hr = cache_from_doc_ns(This->namespaces, &This->node);
2544         if (hr != S_OK)
2545             release_namespaces(This);
2546     }
2547
2548     if (This->namespaces)
2549         return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2550                    &IID_IXMLDOMSchemaCollection, (void**)collection);
2551
2552     return hr;
2553 }
2554
2555 static HRESULT WINAPI domdoc_get_schemas(
2556     IXMLDOMDocument3* iface,
2557     VARIANT* var1 )
2558 {
2559     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2560     HRESULT hr = S_FALSE;
2561     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2562
2563     TRACE("(%p)->(%p)\n", This, var1);
2564
2565     VariantInit(var1); /* Test shows we don't call VariantClear here */
2566     V_VT(var1) = VT_NULL;
2567
2568     if(cur_schema)
2569     {
2570         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2571         if(SUCCEEDED(hr))
2572             V_VT(var1) = VT_DISPATCH;
2573     }
2574     return hr;
2575 }
2576
2577 static HRESULT WINAPI domdoc_putref_schemas(
2578     IXMLDOMDocument3* iface,
2579     VARIANT schema)
2580 {
2581     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2582     HRESULT hr = E_FAIL;
2583     IXMLDOMSchemaCollection2* new_schema = NULL;
2584
2585     FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2586     switch(V_VT(&schema))
2587     {
2588     case VT_UNKNOWN:
2589         hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2590         break;
2591
2592     case VT_DISPATCH:
2593         hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2594         break;
2595
2596     case VT_NULL:
2597     case VT_EMPTY:
2598         hr = S_OK;
2599         break;
2600
2601     default:
2602         WARN("Can't get schema from vt %x\n", V_VT(&schema));
2603     }
2604
2605     if(SUCCEEDED(hr))
2606     {
2607         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2608         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2609     }
2610
2611     return hr;
2612 }
2613
2614 static inline BOOL is_wellformed(xmlDocPtr doc)
2615 {
2616 #ifdef HAVE_XMLDOC_PROPERTIES
2617     return doc->properties & XML_DOC_WELLFORMED;
2618 #else
2619     /* Not a full check, but catches the worst violations */
2620     xmlNodePtr child;
2621     int root = 0;
2622
2623     for (child = doc->children; child != NULL; child = child->next)
2624     {
2625         switch (child->type)
2626         {
2627         case XML_ELEMENT_NODE:
2628             if (++root > 1)
2629                 return FALSE;
2630             break;
2631         case XML_TEXT_NODE:
2632         case XML_CDATA_SECTION_NODE:
2633             return FALSE;
2634             break;
2635         default:
2636             break;
2637         }
2638     }
2639
2640     return root == 1;
2641 #endif
2642 }
2643
2644 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2645 {
2646     va_list ap;
2647     va_start(ap, msg);
2648     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2649     va_end(ap);
2650 }
2651
2652 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2653 {
2654     va_list ap;
2655     va_start(ap, msg);
2656     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2657     va_end(ap);
2658 }
2659
2660 static HRESULT WINAPI domdoc_validateNode(
2661     IXMLDOMDocument3* iface,
2662     IXMLDOMNode* node,
2663     IXMLDOMParseError** err)
2664 {
2665     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2666     LONG state, err_code = 0;
2667     HRESULT hr = S_OK;
2668     int validated = 0;
2669
2670     TRACE("(%p)->(%p, %p)\n", This, node, err);
2671     IXMLDOMDocument3_get_readyState(iface, &state);
2672     if (state != READYSTATE_COMPLETE)
2673     {
2674         if (err)
2675            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2676         return E_PENDING;
2677     }
2678
2679     if (!node)
2680     {
2681         if (err)
2682             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2683         return E_POINTER;
2684     }
2685
2686     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2687     {
2688         if (err)
2689             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2690         return E_FAIL;
2691     }
2692
2693     if (!is_wellformed(get_doc(This)))
2694     {
2695         ERR("doc not well-formed\n");
2696         if (err)
2697             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2698         return S_FALSE;
2699     }
2700
2701     /* DTD validation */
2702     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2703     {
2704         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2705         vctx->error = validate_error;
2706         vctx->warning = validate_warning;
2707         ++validated;
2708
2709         if (!((node == (IXMLDOMNode*)iface)?
2710               xmlValidateDocument(vctx, get_doc(This)) :
2711               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2712         {
2713             /* TODO: get a real error code here */
2714             TRACE("DTD validation failed\n");
2715             err_code = E_XML_INVALID;
2716             hr = S_FALSE;
2717         }
2718         xmlFreeValidCtxt(vctx);
2719     }
2720
2721     /* Schema validation */
2722     if (hr == S_OK && This->properties->schemaCache != NULL)
2723     {
2724
2725         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2726         if (SUCCEEDED(hr))
2727         {
2728             ++validated;
2729             /* TODO: get a real error code here */
2730             if (hr == S_OK)
2731             {
2732                 TRACE("schema validation succeeded\n");
2733             }
2734             else
2735             {
2736                 ERR("schema validation failed\n");
2737                 err_code = E_XML_INVALID;
2738             }
2739         }
2740         else
2741         {
2742             /* not really OK, just didn't find a schema for the ns */
2743             hr = S_OK;
2744         }
2745     }
2746
2747     if (!validated)
2748     {
2749         ERR("no DTD or schema found\n");
2750         err_code = E_XML_NODTD;
2751         hr = S_FALSE;
2752     }
2753
2754     if (err)
2755         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2756
2757     return hr;
2758 }
2759
2760 static HRESULT WINAPI domdoc_validate(
2761     IXMLDOMDocument3* iface,
2762     IXMLDOMParseError** err)
2763 {
2764     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2765     TRACE("(%p)->(%p)\n", This, err);
2766     return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2767 }
2768
2769 static HRESULT WINAPI domdoc_setProperty(
2770     IXMLDOMDocument3* iface,
2771     BSTR p,
2772     VARIANT value)
2773 {
2774     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2775
2776     TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2777
2778     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2779     {
2780         VARIANT varStr;
2781         HRESULT hr;
2782         BSTR bstr;
2783
2784         V_VT(&varStr) = VT_EMPTY;
2785         if (V_VT(&value) != VT_BSTR)
2786         {
2787             if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2788                 return hr;
2789             bstr = V_BSTR(&varStr);
2790         }
2791         else
2792             bstr = V_BSTR(&value);
2793
2794         hr = S_OK;
2795         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2796             This->properties->XPath = TRUE;
2797         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2798             This->properties->XPath = FALSE;
2799         else
2800             hr = E_FAIL;
2801
2802         VariantClear(&varStr);
2803         return hr;
2804     }
2805     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2806     {
2807         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2808         struct list *pNsList;
2809         VARIANT varStr;
2810         HRESULT hr;
2811         BSTR bstr;
2812
2813         V_VT(&varStr) = VT_EMPTY;
2814         if (V_VT(&value) != VT_BSTR)
2815         {
2816             if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2817                 return hr;
2818             bstr = V_BSTR(&varStr);
2819         }
2820         else
2821             bstr = V_BSTR(&value);
2822
2823         hr = S_OK;
2824
2825         pNsList = &(This->properties->selectNsList);
2826         clear_selectNsList(pNsList);
2827         heap_free(nsStr);
2828         nsStr = xmlchar_from_wchar(bstr);
2829
2830         TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2831
2832         This->properties->selectNsStr = nsStr;
2833         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2834         if (bstr && *bstr)
2835         {
2836             xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2837             select_ns_entry* ns_entry = NULL;
2838             xmlXPathContextPtr ctx;
2839
2840             ctx = xmlXPathNewContext(This->node.node->doc);
2841             pTokBegin = nsStr;
2842
2843             /* skip leading spaces */
2844             while (*pTokBegin == ' '  || *pTokBegin == '\n' ||
2845                    *pTokBegin == '\t' || *pTokBegin == '\r')
2846                 ++pTokBegin;
2847
2848             for (; *pTokBegin; pTokBegin = pTokEnd)
2849             {
2850                 if (ns_entry)
2851                     memset(ns_entry, 0, sizeof(select_ns_entry));
2852                 else
2853                     ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2854
2855                 while (*pTokBegin == ' ')
2856                     ++pTokBegin;
2857                 pTokEnd = pTokBegin;
2858                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2859                     ++pTokEnd;
2860
2861                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2862                 {
2863                     hr = E_FAIL;
2864                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2865                           debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2866                     continue;
2867                 }
2868
2869                 pTokBegin += 5;
2870                 if (*pTokBegin == '=')
2871                 {
2872                     /*valid for XSLPattern?*/
2873                     FIXME("Setting default xmlns not supported - skipping.\n");
2874                     continue;
2875                 }
2876                 else if (*pTokBegin == ':')
2877                 {
2878                     ns_entry->prefix = ++pTokBegin;
2879                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2880                         ;
2881
2882                     if (pTokInner == pTokEnd)
2883                     {
2884                         hr = E_FAIL;
2885                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2886                               debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2887                         continue;
2888                     }
2889
2890                     ns_entry->prefix_end = *pTokInner;
2891                     *pTokInner = 0;
2892                     ++pTokInner;
2893
2894                     if (pTokEnd-pTokInner > 1 &&
2895                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2896                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2897                     {
2898                         ns_entry->href = ++pTokInner;
2899                         ns_entry->href_end = *(pTokEnd-1);
2900                         *(pTokEnd-1) = 0;
2901                         list_add_tail(pNsList, &ns_entry->entry);
2902                         /*let libxml figure out if they're valid from here ;)*/
2903                         if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2904                         {
2905                             hr = E_FAIL;
2906                         }
2907                         ns_entry = NULL;
2908                         continue;
2909                     }
2910                     else
2911                     {
2912                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2913                               debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2914                         list_add_tail(pNsList, &ns_entry->entry);
2915
2916                         ns_entry = NULL;
2917                         hr = E_FAIL;
2918                         continue;
2919                     }
2920                 }
2921                 else
2922                 {
2923                     hr = E_FAIL;
2924                     continue;
2925                 }
2926             }
2927             heap_free(ns_entry);
2928             xmlXPathFreeContext(ctx);
2929         }
2930
2931         VariantClear(&varStr);
2932         return hr;
2933     }
2934     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2935              lstrcmpiW(p, PropertyNewParserW) == 0 ||
2936              lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2937     {
2938         /* Ignore */
2939         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2940         return S_OK;
2941     }
2942
2943     FIXME("Unknown property %s\n", debugstr_w(p));
2944     return E_FAIL;
2945 }
2946
2947 static HRESULT WINAPI domdoc_getProperty(
2948     IXMLDOMDocument3* iface,
2949     BSTR p,
2950     VARIANT* var)
2951 {
2952     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2953
2954     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2955
2956     if (!var)
2957         return E_INVALIDARG;
2958
2959     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2960     {
2961         V_VT(var) = VT_BSTR;
2962         V_BSTR(var) = This->properties->XPath ?
2963                       SysAllocString(PropValueXPathW) :
2964                       SysAllocString(PropValueXSLPatternW);
2965         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2966     }
2967     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2968     {
2969         int lenA, lenW;
2970         BSTR rebuiltStr, cur;
2971         const xmlChar *nsStr;
2972         struct list *pNsList;
2973         select_ns_entry* pNsEntry;
2974
2975         V_VT(var) = VT_BSTR;
2976         nsStr = This->properties->selectNsStr;
2977         pNsList = &This->properties->selectNsList;
2978         lenA = This->properties->selectNsStr_len;
2979         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2980         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2981         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2982         cur = rebuiltStr;
2983         /* this is fine because all of the chars that end tokens are ASCII*/
2984         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2985         {
2986             while (*cur != 0) ++cur;
2987             if (pNsEntry->prefix_end)
2988             {
2989                 *cur = pNsEntry->prefix_end;
2990                 while (*cur != 0) ++cur;
2991             }
2992
2993             if (pNsEntry->href_end)
2994             {
2995                 *cur = pNsEntry->href_end;
2996             }
2997         }
2998         V_BSTR(var) = SysAllocString(rebuiltStr);
2999         heap_free(rebuiltStr);
3000         return S_OK;
3001     }
3002
3003     FIXME("Unknown property %s\n", debugstr_w(p));
3004     return E_FAIL;
3005 }
3006
3007 static HRESULT WINAPI domdoc_importNode(
3008     IXMLDOMDocument3* iface,
3009     IXMLDOMNode* node,
3010     VARIANT_BOOL deep,
3011     IXMLDOMNode** clone)
3012 {
3013     domdoc *This = impl_from_IXMLDOMDocument3( iface );
3014     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3015     return E_NOTIMPL;
3016 }
3017
3018 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3019 {
3020     domdoc_QueryInterface,
3021     domdoc_AddRef,
3022     domdoc_Release,
3023     domdoc_GetTypeInfoCount,
3024     domdoc_GetTypeInfo,
3025     domdoc_GetIDsOfNames,
3026     domdoc_Invoke,
3027     domdoc_get_nodeName,
3028     domdoc_get_nodeValue,
3029     domdoc_put_nodeValue,
3030     domdoc_get_nodeType,
3031     domdoc_get_parentNode,
3032     domdoc_get_childNodes,
3033     domdoc_get_firstChild,
3034     domdoc_get_lastChild,
3035     domdoc_get_previousSibling,
3036     domdoc_get_nextSibling,
3037     domdoc_get_attributes,
3038     domdoc_insertBefore,
3039     domdoc_replaceChild,
3040     domdoc_removeChild,
3041     domdoc_appendChild,
3042     domdoc_hasChildNodes,
3043     domdoc_get_ownerDocument,
3044     domdoc_cloneNode,
3045     domdoc_get_nodeTypeString,
3046     domdoc_get_text,
3047     domdoc_put_text,
3048     domdoc_get_specified,
3049     domdoc_get_definition,
3050     domdoc_get_nodeTypedValue,
3051     domdoc_put_nodeTypedValue,
3052     domdoc_get_dataType,
3053     domdoc_put_dataType,
3054     domdoc_get_xml,
3055     domdoc_transformNode,
3056     domdoc_selectNodes,
3057     domdoc_selectSingleNode,
3058     domdoc_get_parsed,
3059     domdoc_get_namespaceURI,
3060     domdoc_get_prefix,
3061     domdoc_get_baseName,
3062     domdoc_transformNodeToObject,
3063     domdoc_get_doctype,
3064     domdoc_get_implementation,
3065     domdoc_get_documentElement,
3066     domdoc_put_documentElement,
3067     domdoc_createElement,
3068     domdoc_createDocumentFragment,
3069     domdoc_createTextNode,
3070     domdoc_createComment,
3071     domdoc_createCDATASection,
3072     domdoc_createProcessingInstruction,
3073     domdoc_createAttribute,
3074     domdoc_createEntityReference,
3075     domdoc_getElementsByTagName,
3076     domdoc_createNode,
3077     domdoc_nodeFromID,
3078     domdoc_load,
3079     domdoc_get_readyState,
3080     domdoc_get_parseError,
3081     domdoc_get_url,
3082     domdoc_get_async,
3083     domdoc_put_async,
3084     domdoc_abort,
3085     domdoc_loadXML,
3086     domdoc_save,
3087     domdoc_get_validateOnParse,
3088     domdoc_put_validateOnParse,
3089     domdoc_get_resolveExternals,
3090     domdoc_put_resolveExternals,
3091     domdoc_get_preserveWhiteSpace,
3092     domdoc_put_preserveWhiteSpace,
3093     domdoc_put_onreadystatechange,
3094     domdoc_put_onDataAvailable,
3095     domdoc_put_onTransformNode,
3096     domdoc_get_namespaces,
3097     domdoc_get_schemas,
3098     domdoc_putref_schemas,
3099     domdoc_validate,
3100     domdoc_setProperty,
3101     domdoc_getProperty,
3102     domdoc_validateNode,
3103     domdoc_importNode
3104 };
3105
3106 /* IConnectionPointContainer */
3107 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3108                                                               REFIID riid, void **ppv)
3109 {
3110     domdoc *This = impl_from_IConnectionPointContainer(iface);
3111     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3112 }
3113
3114 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3115 {
3116     domdoc *This = impl_from_IConnectionPointContainer(iface);
3117     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3118 }
3119
3120 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3121 {
3122     domdoc *This = impl_from_IConnectionPointContainer(iface);
3123     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3124 }
3125
3126 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3127         IEnumConnectionPoints **ppEnum)
3128 {
3129     domdoc *This = impl_from_IConnectionPointContainer(iface);
3130     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3131     return E_NOTIMPL;
3132 }
3133
3134 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3135         REFIID riid, IConnectionPoint **cp)
3136 {
3137     domdoc *This = impl_from_IConnectionPointContainer(iface);
3138     ConnectionPoint *iter;
3139
3140     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3141
3142     *cp = NULL;
3143
3144     for(iter = This->cp_list; iter; iter = iter->next)
3145     {
3146         if (IsEqualGUID(iter->iid, riid))
3147             *cp = &iter->IConnectionPoint_iface;
3148     }
3149
3150     if (*cp)
3151     {
3152         IConnectionPoint_AddRef(*cp);
3153         return S_OK;
3154     }
3155
3156     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3157     return CONNECT_E_NOCONNECTION;
3158
3159 }
3160
3161 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3162 {
3163     ConnectionPointContainer_QueryInterface,
3164     ConnectionPointContainer_AddRef,
3165     ConnectionPointContainer_Release,
3166     ConnectionPointContainer_EnumConnectionPoints,
3167     ConnectionPointContainer_FindConnectionPoint
3168 };
3169
3170 /* IConnectionPoint */
3171 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3172                                                      REFIID riid, void **ppv)
3173 {
3174     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3175
3176     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3177
3178     *ppv = NULL;
3179
3180     if (IsEqualGUID(&IID_IUnknown, riid) ||
3181         IsEqualGUID(&IID_IConnectionPoint, riid))
3182     {
3183         *ppv = iface;
3184     }
3185
3186     if (*ppv)
3187     {
3188         IConnectionPoint_AddRef(iface);
3189         return S_OK;
3190     }
3191
3192     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3193     return E_NOINTERFACE;
3194 }
3195
3196 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3197 {
3198     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3199     return IConnectionPointContainer_AddRef(This->container);
3200 }
3201
3202 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3203 {
3204     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3205     return IConnectionPointContainer_Release(This->container);
3206 }
3207
3208 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3209 {
3210     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3211
3212     TRACE("(%p)->(%p)\n", This, iid);
3213
3214     if (!iid) return E_POINTER;
3215
3216     *iid = *This->iid;
3217     return S_OK;
3218 }
3219
3220 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3221         IConnectionPointContainer **container)
3222 {
3223     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3224
3225     TRACE("(%p)->(%p)\n", This, container);
3226
3227     if (!container) return E_POINTER;
3228
3229     *container = This->container;
3230     IConnectionPointContainer_AddRef(*container);
3231     return S_OK;
3232 }
3233
3234 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3235                                              DWORD *pdwCookie)
3236 {
3237     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3238     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3239     return E_NOTIMPL;
3240 }
3241
3242 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3243 {
3244     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3245
3246     TRACE("(%p)->(%d)\n", This, cookie);
3247
3248     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3249         return CONNECT_E_NOCONNECTION;
3250
3251     IUnknown_Release(This->sinks[cookie-1].unk);
3252     This->sinks[cookie-1].unk = NULL;
3253
3254     return S_OK;
3255 }
3256
3257 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3258                                                       IEnumConnections **ppEnum)
3259 {
3260     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3261     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3262     return E_NOTIMPL;
3263 }
3264
3265 static const IConnectionPointVtbl ConnectionPointVtbl =
3266 {
3267     ConnectionPoint_QueryInterface,
3268     ConnectionPoint_AddRef,
3269     ConnectionPoint_Release,
3270     ConnectionPoint_GetConnectionInterface,
3271     ConnectionPoint_GetConnectionPointContainer,
3272     ConnectionPoint_Advise,
3273     ConnectionPoint_Unadvise,
3274     ConnectionPoint_EnumConnections
3275 };
3276
3277 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3278 {
3279     cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3280     cp->doc = doc;
3281     cp->iid = riid;
3282     cp->sinks = NULL;
3283     cp->sinks_size = 0;
3284
3285     cp->next = doc->cp_list;
3286     doc->cp_list = cp;
3287
3288     cp->container = &doc->IConnectionPointContainer_iface;
3289 }
3290
3291 /* domdoc implementation of IObjectWithSite */
3292 static HRESULT WINAPI
3293 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3294 {
3295     domdoc *This = impl_from_IObjectWithSite(iface);
3296     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3297 }
3298
3299 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3300 {
3301     domdoc *This = impl_from_IObjectWithSite(iface);
3302     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3303 }
3304
3305 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3306 {
3307     domdoc *This = impl_from_IObjectWithSite(iface);
3308     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3309 }
3310
3311 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3312 {
3313     domdoc *This = impl_from_IObjectWithSite(iface);
3314
3315     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3316
3317     if ( !This->site )
3318         return E_FAIL;
3319
3320     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3321 }
3322
3323 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3324 {
3325     domdoc *This = impl_from_IObjectWithSite(iface);
3326
3327     TRACE("(%p)->(%p)\n", iface, punk);
3328
3329     if(!punk)
3330     {
3331         if(This->site)
3332         {
3333             IUnknown_Release( This->site );
3334             This->site = NULL;
3335         }
3336
3337         return S_OK;
3338     }
3339
3340     IUnknown_AddRef( punk );
3341
3342     if(This->site)
3343         IUnknown_Release( This->site );
3344
3345     This->site = punk;
3346
3347     return S_OK;
3348 }
3349
3350 static const IObjectWithSiteVtbl domdocObjectSite =
3351 {
3352     domdoc_ObjectWithSite_QueryInterface,
3353     domdoc_ObjectWithSite_AddRef,
3354     domdoc_ObjectWithSite_Release,
3355     domdoc_ObjectWithSite_SetSite,
3356     domdoc_ObjectWithSite_GetSite
3357 };
3358
3359 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3360 {
3361     domdoc *This = impl_from_IObjectSafety(iface);
3362     return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3363 }
3364
3365 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3366 {
3367     domdoc *This = impl_from_IObjectSafety(iface);
3368     return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3369 }
3370
3371 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3372 {
3373     domdoc *This = impl_from_IObjectSafety(iface);
3374     return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3375 }
3376
3377 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3378
3379 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3380         DWORD *supported, DWORD *enabled)
3381 {
3382     domdoc *This = impl_from_IObjectSafety(iface);
3383
3384     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3385
3386     if(!supported || !enabled) return E_POINTER;
3387
3388     *supported = SAFETY_SUPPORTED_OPTIONS;
3389     *enabled = This->safeopt;
3390
3391     return S_OK;
3392 }
3393
3394 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3395         DWORD mask, DWORD enabled)
3396 {
3397     domdoc *This = impl_from_IObjectSafety(iface);
3398     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3399
3400     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3401         return E_FAIL;
3402
3403     This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3404
3405     return S_OK;
3406 }
3407
3408 #undef SAFETY_SUPPORTED_OPTIONS
3409
3410 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3411     domdoc_Safety_QueryInterface,
3412     domdoc_Safety_AddRef,
3413     domdoc_Safety_Release,
3414     domdoc_Safety_GetInterfaceSafetyOptions,
3415     domdoc_Safety_SetInterfaceSafetyOptions
3416 };
3417
3418 static const tid_t domdoc_iface_tids[] = {
3419     IXMLDOMDocument3_tid,
3420     0
3421 };
3422
3423 static dispex_static_data_t domdoc_dispex = {
3424     NULL,
3425     IXMLDOMDocument3_tid,
3426     NULL,
3427     domdoc_iface_tids
3428 };
3429
3430 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3431 {
3432     domdoc *doc;
3433
3434     doc = heap_alloc( sizeof (*doc) );
3435     if( !doc )
3436         return E_OUTOFMEMORY;
3437
3438     doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3439     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3440     doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3441     doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3442     doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3443     doc->ref = 1;
3444     doc->async = VARIANT_TRUE;
3445     doc->validating = 0;
3446     doc->resolving = 0;
3447     doc->properties = properties_from_xmlDocPtr(xmldoc);
3448     doc->error = S_OK;
3449     doc->stream = NULL;
3450     doc->site = NULL;
3451     doc->safeopt = 0;
3452     doc->bsc = NULL;
3453     doc->cp_list = NULL;
3454     doc->namespaces = NULL;
3455     memset(doc->events, 0, sizeof(doc->events));
3456
3457     /* events connection points */
3458     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3459     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3460     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3461
3462     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3463             &domdoc_dispex);
3464
3465     *document = &doc->IXMLDOMDocument3_iface;
3466
3467     TRACE("returning iface %p\n", *document);
3468     return S_OK;
3469 }
3470
3471 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3472 {
3473     xmlDocPtr xmldoc;
3474     HRESULT hr;
3475
3476     TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3477
3478     xmldoc = xmlNewDoc(NULL);
3479     if(!xmldoc)
3480         return E_OUTOFMEMORY;
3481
3482     xmldoc_init(xmldoc, version);
3483
3484     hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3485     if(FAILED(hr))
3486     {
3487         free_properties(properties_from_xmlDocPtr(xmldoc));
3488         heap_free(xmldoc->_private);
3489         xmlFreeDoc(xmldoc);
3490         return hr;
3491     }
3492
3493     return hr;
3494 }
3495
3496 IUnknown* create_domdoc( xmlNodePtr document )
3497 {
3498     void* pObj = NULL;
3499     HRESULT hr;
3500
3501     TRACE("(%p)\n", document);
3502
3503     hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3504     if (FAILED(hr))
3505         return NULL;
3506
3507     return pObj;
3508 }
3509
3510 #else
3511
3512 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3513 {
3514     MESSAGE("This program tried to use a DOMDocument object, but\n"
3515             "libxml2 support was not present at compile time.\n");
3516     return E_NOTIMPL;
3517 }
3518
3519 #endif