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