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