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