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