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