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