mshtml: Improved error handling in HTMLElement_Create calls.
[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     return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1284 }
1285
1286 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1287     IXMLDOMDocument3 *iface,
1288     VARIANT typedValue )
1289 {
1290     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1291     return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1292 }
1293
1294
1295 static HRESULT WINAPI domdoc_get_dataType(
1296     IXMLDOMDocument3 *iface,
1297     VARIANT* typename )
1298 {
1299     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1300     TRACE("(%p)->(%p)\n", This, typename);
1301     return return_null_var( typename );
1302 }
1303
1304
1305 static HRESULT WINAPI domdoc_put_dataType(
1306     IXMLDOMDocument3 *iface,
1307     BSTR dataTypeName )
1308 {
1309     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1310     return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), dataTypeName );
1311 }
1312
1313 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1314 {
1315     return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1316 }
1317
1318 static HRESULT WINAPI domdoc_get_xml(
1319     IXMLDOMDocument3 *iface,
1320     BSTR* p)
1321 {
1322     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1323     xmlSaveCtxtPtr ctxt;
1324     xmlBufferPtr buf;
1325     int options;
1326     long ret;
1327
1328     TRACE("(%p)->(%p)\n", This, p);
1329
1330     if(!p)
1331         return E_INVALIDARG;
1332
1333     *p = NULL;
1334
1335     buf = xmlBufferCreate();
1336     if(!buf)
1337         return E_OUTOFMEMORY;
1338
1339     options  = xmldoc_has_decl(get_doc(This)) ? XML_SAVE_NO_DECL : 0;
1340     options |= XML_SAVE_FORMAT;
1341     ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1342
1343     if(!ctxt)
1344     {
1345         xmlBufferFree(buf);
1346         return E_OUTOFMEMORY;
1347     }
1348
1349     ret = xmlSaveDoc(ctxt, get_doc(This));
1350     /* flushes on close */
1351     xmlSaveClose(ctxt);
1352
1353     TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1354     if(ret != -1 && xmlBufferLength(buf) > 0)
1355     {
1356         BSTR content;
1357
1358         content = bstr_from_xmlChar(xmlBufferContent(buf));
1359         content = EnsureCorrectEOL(content);
1360
1361         *p = content;
1362     }
1363     else
1364     {
1365         *p = SysAllocStringLen(NULL, 0);
1366     }
1367
1368     xmlBufferFree(buf);
1369
1370     return *p ? S_OK : E_OUTOFMEMORY;
1371 }
1372
1373
1374 static HRESULT WINAPI domdoc_transformNode(
1375     IXMLDOMDocument3 *iface,
1376     IXMLDOMNode* styleSheet,
1377     BSTR* xmlString )
1378 {
1379     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1380     return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), styleSheet, xmlString );
1381 }
1382
1383
1384 static HRESULT WINAPI domdoc_selectNodes(
1385     IXMLDOMDocument3 *iface,
1386     BSTR queryString,
1387     IXMLDOMNodeList** resultList )
1388 {
1389     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1390     return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), queryString, resultList );
1391 }
1392
1393
1394 static HRESULT WINAPI domdoc_selectSingleNode(
1395     IXMLDOMDocument3 *iface,
1396     BSTR queryString,
1397     IXMLDOMNode** resultNode )
1398 {
1399     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1400     return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), queryString, resultNode );
1401 }
1402
1403
1404 static HRESULT WINAPI domdoc_get_parsed(
1405     IXMLDOMDocument3 *iface,
1406     VARIANT_BOOL* isParsed )
1407 {
1408     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409     FIXME("(%p)->(%p) stub!\n", This, isParsed);
1410     *isParsed = VARIANT_TRUE;
1411     return S_OK;
1412 }
1413
1414
1415 static HRESULT WINAPI domdoc_get_namespaceURI(
1416     IXMLDOMDocument3 *iface,
1417     BSTR* namespaceURI )
1418 {
1419     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1420     return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), namespaceURI );
1421 }
1422
1423
1424 static HRESULT WINAPI domdoc_get_prefix(
1425     IXMLDOMDocument3 *iface,
1426     BSTR* prefix )
1427 {
1428     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1429     TRACE("(%p)->(%p)\n", This, prefix);
1430     return return_null_bstr( prefix );
1431 }
1432
1433
1434 static HRESULT WINAPI domdoc_get_baseName(
1435     IXMLDOMDocument3 *iface,
1436     BSTR* name )
1437 {
1438     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1439     TRACE("(%p)->(%p)\n", This, name);
1440     return return_null_bstr( name );
1441 }
1442
1443
1444 static HRESULT WINAPI domdoc_transformNodeToObject(
1445     IXMLDOMDocument3 *iface,
1446     IXMLDOMNode* stylesheet,
1447     VARIANT outputObject)
1448 {
1449     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1450     return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), stylesheet, outputObject );
1451 }
1452
1453
1454 static HRESULT WINAPI domdoc_get_doctype(
1455     IXMLDOMDocument3 *iface,
1456     IXMLDOMDocumentType** documentType )
1457 {
1458     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1459     FIXME("(%p)\n", This);
1460     return E_NOTIMPL;
1461 }
1462
1463
1464 static HRESULT WINAPI domdoc_get_implementation(
1465     IXMLDOMDocument3 *iface,
1466     IXMLDOMImplementation** impl )
1467 {
1468     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1469
1470     TRACE("(%p)->(%p)\n", This, impl);
1471
1472     if(!impl)
1473         return E_INVALIDARG;
1474
1475     *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1476
1477     return S_OK;
1478 }
1479
1480 static HRESULT WINAPI domdoc_get_documentElement(
1481     IXMLDOMDocument3 *iface,
1482     IXMLDOMElement** DOMElement )
1483 {
1484     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1485     IXMLDOMNode *element_node;
1486     xmlNodePtr root;
1487     HRESULT hr;
1488
1489     TRACE("(%p)->(%p)\n", This, DOMElement);
1490
1491     if(!DOMElement)
1492         return E_INVALIDARG;
1493
1494     *DOMElement = NULL;
1495
1496     root = xmlDocGetRootElement( get_doc(This) );
1497     if ( !root )
1498         return S_FALSE;
1499
1500     element_node = create_node( root );
1501     if(!element_node) return S_FALSE;
1502
1503     hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1504     IXMLDOMNode_Release(element_node);
1505
1506     return hr;
1507 }
1508
1509
1510 static HRESULT WINAPI domdoc_put_documentElement(
1511     IXMLDOMDocument3 *iface,
1512     IXMLDOMElement* DOMElement )
1513 {
1514     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1515     IXMLDOMNode *elementNode;
1516     xmlNodePtr oldRoot;
1517     xmlnode *xmlNode;
1518     HRESULT hr;
1519
1520     TRACE("(%p)->(%p)\n", This, DOMElement);
1521
1522     hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1523     if(FAILED(hr))
1524         return hr;
1525
1526     xmlNode = get_node_obj( elementNode );
1527     if(!xmlNode) {
1528         FIXME("elementNode is not our object\n");
1529         return E_FAIL;
1530     }
1531
1532     if(!xmlNode->node->parent)
1533         if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1534             WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1535
1536     oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1537     IXMLDOMNode_Release( elementNode );
1538
1539     if(oldRoot)
1540         xmldoc_add_orphan(oldRoot->doc, oldRoot);
1541
1542     return S_OK;
1543 }
1544
1545
1546 static HRESULT WINAPI domdoc_createElement(
1547     IXMLDOMDocument3 *iface,
1548     BSTR tagname,
1549     IXMLDOMElement** element )
1550 {
1551     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1552     IXMLDOMNode *node;
1553     VARIANT type;
1554     HRESULT hr;
1555
1556     TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1557
1558     if (!element || !tagname) return E_INVALIDARG;
1559
1560     V_VT(&type) = VT_I1;
1561     V_I1(&type) = NODE_ELEMENT;
1562
1563     hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1564     if (hr == S_OK)
1565     {
1566         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1567         IXMLDOMNode_Release(node);
1568     }
1569
1570     return hr;
1571 }
1572
1573
1574 static HRESULT WINAPI domdoc_createDocumentFragment(
1575     IXMLDOMDocument3 *iface,
1576     IXMLDOMDocumentFragment** frag )
1577 {
1578     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1579     IXMLDOMNode *node;
1580     VARIANT type;
1581     HRESULT hr;
1582
1583     TRACE("(%p)->(%p)\n", This, frag);
1584
1585     if (!frag) return E_INVALIDARG;
1586
1587     *frag = NULL;
1588
1589     V_VT(&type) = VT_I1;
1590     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1591
1592     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1593     if (hr == S_OK)
1594     {
1595         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1596         IXMLDOMNode_Release(node);
1597     }
1598
1599     return hr;
1600 }
1601
1602
1603 static HRESULT WINAPI domdoc_createTextNode(
1604     IXMLDOMDocument3 *iface,
1605     BSTR data,
1606     IXMLDOMText** text )
1607 {
1608     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1609     IXMLDOMNode *node;
1610     VARIANT type;
1611     HRESULT hr;
1612
1613     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1614
1615     if (!text) return E_INVALIDARG;
1616
1617     *text = NULL;
1618
1619     V_VT(&type) = VT_I1;
1620     V_I1(&type) = NODE_TEXT;
1621
1622     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1623     if (hr == S_OK)
1624     {
1625         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1626         IXMLDOMNode_Release(node);
1627         hr = IXMLDOMText_put_data(*text, data);
1628     }
1629
1630     return hr;
1631 }
1632
1633
1634 static HRESULT WINAPI domdoc_createComment(
1635     IXMLDOMDocument3 *iface,
1636     BSTR data,
1637     IXMLDOMComment** comment )
1638 {
1639     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1640     VARIANT type;
1641     HRESULT hr;
1642     IXMLDOMNode *node;
1643
1644     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1645
1646     if (!comment) return E_INVALIDARG;
1647
1648     *comment = NULL;
1649
1650     V_VT(&type) = VT_I1;
1651     V_I1(&type) = NODE_COMMENT;
1652
1653     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1654     if (hr == S_OK)
1655     {
1656         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1657         IXMLDOMNode_Release(node);
1658         hr = IXMLDOMComment_put_data(*comment, data);
1659     }
1660
1661     return hr;
1662 }
1663
1664
1665 static HRESULT WINAPI domdoc_createCDATASection(
1666     IXMLDOMDocument3 *iface,
1667     BSTR data,
1668     IXMLDOMCDATASection** cdata )
1669 {
1670     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1671     IXMLDOMNode *node;
1672     VARIANT type;
1673     HRESULT hr;
1674
1675     TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1676
1677     if (!cdata) return E_INVALIDARG;
1678
1679     *cdata = NULL;
1680
1681     V_VT(&type) = VT_I1;
1682     V_I1(&type) = NODE_CDATA_SECTION;
1683
1684     hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1685     if (hr == S_OK)
1686     {
1687         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1688         IXMLDOMNode_Release(node);
1689         hr = IXMLDOMCDATASection_put_data(*cdata, data);
1690     }
1691
1692     return hr;
1693 }
1694
1695
1696 static HRESULT WINAPI domdoc_createProcessingInstruction(
1697     IXMLDOMDocument3 *iface,
1698     BSTR target,
1699     BSTR data,
1700     IXMLDOMProcessingInstruction** pi )
1701 {
1702     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1703     IXMLDOMNode *node;
1704     VARIANT type;
1705     HRESULT hr;
1706
1707     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1708
1709     if (!pi) return E_INVALIDARG;
1710
1711     *pi = NULL;
1712
1713     V_VT(&type) = VT_I1;
1714     V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1715
1716     hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1717     if (hr == S_OK)
1718     {
1719         xmlnode *node_obj;
1720
1721         /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1722         node_obj = get_node_obj(node);
1723         hr = node_set_content(node_obj, data);
1724
1725         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1726         IXMLDOMNode_Release(node);
1727     }
1728
1729     return hr;
1730 }
1731
1732
1733 static HRESULT WINAPI domdoc_createAttribute(
1734     IXMLDOMDocument3 *iface,
1735     BSTR name,
1736     IXMLDOMAttribute** attribute )
1737 {
1738     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1739     IXMLDOMNode *node;
1740     VARIANT type;
1741     HRESULT hr;
1742
1743     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1744
1745     if (!attribute || !name) return E_INVALIDARG;
1746
1747     V_VT(&type) = VT_I1;
1748     V_I1(&type) = NODE_ATTRIBUTE;
1749
1750     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1751     if (hr == S_OK)
1752     {
1753         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1754         IXMLDOMNode_Release(node);
1755     }
1756
1757     return hr;
1758 }
1759
1760
1761 static HRESULT WINAPI domdoc_createEntityReference(
1762     IXMLDOMDocument3 *iface,
1763     BSTR name,
1764     IXMLDOMEntityReference** entityref )
1765 {
1766     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1767     IXMLDOMNode *node;
1768     VARIANT type;
1769     HRESULT hr;
1770
1771     TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1772
1773     if (!entityref) return E_INVALIDARG;
1774
1775     *entityref = NULL;
1776
1777     V_VT(&type) = VT_I1;
1778     V_I1(&type) = NODE_ENTITY_REFERENCE;
1779
1780     hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1781     if (hr == S_OK)
1782     {
1783         IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1784         IXMLDOMNode_Release(node);
1785     }
1786
1787     return hr;
1788 }
1789
1790 xmlChar* tagName_to_XPath(const BSTR tagName)
1791 {
1792     xmlChar *query, *tmp;
1793     static const xmlChar mod_pre[] = "*[local-name()='";
1794     static const xmlChar mod_post[] = "']";
1795     static const xmlChar prefix[] = "descendant::";
1796     const WCHAR *tokBegin, *tokEnd;
1797     int len;
1798
1799     query = xmlStrdup(prefix);
1800
1801     tokBegin = tagName;
1802     while (tokBegin && *tokBegin)
1803     {
1804         switch (*tokBegin)
1805         {
1806         case '/':
1807             query = xmlStrcat(query, BAD_CAST "/");
1808             ++tokBegin;
1809             break;
1810         case '*':
1811             query = xmlStrcat(query, BAD_CAST "*");
1812             ++tokBegin;
1813             break;
1814         default:
1815             query = xmlStrcat(query, mod_pre);
1816             tokEnd = tokBegin;
1817             while (*tokEnd && *tokEnd != '/')
1818                 ++tokEnd;
1819             len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1820             tmp = xmlMalloc(len);
1821             WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1822             query = xmlStrncat(query, tmp, len);
1823             xmlFree(tmp);
1824             tokBegin = tokEnd;
1825             query = xmlStrcat(query, mod_post);
1826         }
1827     }
1828
1829     return query;
1830 }
1831
1832 static HRESULT WINAPI domdoc_getElementsByTagName(
1833     IXMLDOMDocument3 *iface,
1834     BSTR tagName,
1835     IXMLDOMNodeList** resultList )
1836 {
1837     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1838     xmlChar *query;
1839     HRESULT hr;
1840     BOOL XPath;
1841
1842     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1843
1844     if (!tagName || !resultList) return E_INVALIDARG;
1845
1846     XPath = This->properties->XPath;
1847     This->properties->XPath = TRUE;
1848     query = tagName_to_XPath(tagName);
1849     hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
1850     xmlFree(query);
1851     This->properties->XPath = XPath;
1852
1853     return hr;
1854 }
1855
1856 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1857 {
1858     VARIANT tmp;
1859     HRESULT hr;
1860
1861     VariantInit(&tmp);
1862     hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1863     if(FAILED(hr))
1864         return E_INVALIDARG;
1865
1866     *type = V_I4(&tmp);
1867
1868     return S_OK;
1869 }
1870
1871 static HRESULT WINAPI domdoc_createNode(
1872     IXMLDOMDocument3 *iface,
1873     VARIANT Type,
1874     BSTR name,
1875     BSTR namespaceURI,
1876     IXMLDOMNode** node )
1877 {
1878     domdoc *This = impl_from_IXMLDOMDocument3( iface );
1879     DOMNodeType node_type;
1880     xmlNodePtr xmlnode;
1881     xmlChar *xml_name, *href;
1882     HRESULT hr;
1883
1884     TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1885
1886     if(!node) return E_INVALIDARG;
1887
1888     hr = get_node_type(Type, &node_type);
1889     if(FAILED(hr)) return hr;
1890
1891     if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1892         FIXME("nodes with namespaces currently not supported.\n");
1893
1894     TRACE("node_type %d\n", node_type);
1895
1896     /* exit earlier for types that need name */
1897     switch(node_type)
1898     {
1899     case NODE_ELEMENT:
1900     case NODE_ATTRIBUTE:
1901     case NODE_ENTITY_REFERENCE:
1902     case NODE_PROCESSING_INSTRUCTION:
1903         if (!name || *name == 0) return E_FAIL;
1904     default:
1905         break;
1906     }
1907
1908     xml_name = xmlChar_from_wchar(name);
1909     /* prevent empty href to be allocated */
1910     href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1911
1912     switch(node_type)
1913     {
1914     case NODE_ELEMENT:
1915     {
1916         xmlChar *local, *prefix;
1917
1918         local = xmlSplitQName2(xml_name, &prefix);
1919
1920         xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1921
1922         /* allow to create default namespace xmlns= */
1923         if (local || (href && *href))
1924         {
1925             xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1926             xmlSetNs(xmlnode, ns);
1927         }
1928
1929         xmlFree(local);
1930         xmlFree(prefix);
1931
1932         break;
1933     }
1934     case NODE_ATTRIBUTE:
1935         xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1936         break;
1937     case NODE_TEXT:
1938         xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1939         break;
1940     case NODE_CDATA_SECTION:
1941         xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1942         break;
1943     case NODE_ENTITY_REFERENCE:
1944         xmlnode = xmlNewReference(get_doc(This), xml_name);
1945         break;
1946     case NODE_PROCESSING_INSTRUCTION:
1947 #ifdef HAVE_XMLNEWDOCPI
1948         xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1949 #else
1950         FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1951         xmlnode = NULL;
1952 #endif
1953         break;
1954     case NODE_COMMENT:
1955         xmlnode = xmlNewDocComment(get_doc(This), NULL);
1956         break;
1957     case NODE_DOCUMENT_FRAGMENT:
1958         xmlnode = xmlNewDocFragment(get_doc(This));
1959         break;
1960     /* unsupported types */
1961     case NODE_DOCUMENT:
1962     case NODE_DOCUMENT_TYPE:
1963     case NODE_ENTITY:
1964     case NODE_NOTATION:
1965         heap_free(xml_name);
1966         return E_INVALIDARG;
1967     default:
1968         FIXME("unhandled node type %d\n", node_type);
1969         xmlnode = NULL;
1970         break;
1971     }
1972
1973     *node = create_node(xmlnode);
1974     heap_free(xml_name);
1975     heap_free(href);
1976
1977     if(*node)
1978     {
1979         TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1980         xmldoc_add_orphan(xmlnode->doc, xmlnode);
1981         return S_OK;
1982     }
1983
1984     return E_FAIL;
1985 }
1986
1987 static HRESULT WINAPI domdoc_nodeFromID(
1988     IXMLDOMDocument3 *iface,
1989     BSTR idString,
1990     IXMLDOMNode** node )
1991 {
1992     domdoc *This = impl_from_IXMLDOMDocument3(iface);
1993     FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1994     return E_NOTIMPL;
1995 }
1996
1997 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1998 {
1999     domdoc *This = obj;
2000     xmlDocPtr xmldoc;
2001
2002     xmldoc = doparse(This, ptr, len, NULL);
2003     if(xmldoc) {
2004         xmldoc->_private = create_priv();
2005         return attach_xmldoc(This, xmldoc);
2006     }
2007
2008     return S_OK;
2009 }
2010
2011 static HRESULT doread( domdoc *This, LPWSTR filename )
2012 {
2013     bsc_t *bsc;
2014     HRESULT hr;
2015
2016     hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2017     if(FAILED(hr))
2018         return hr;
2019
2020     if(This->bsc)
2021         detach_bsc(This->bsc);
2022
2023     This->bsc = bsc;
2024     return S_OK;
2025 }
2026
2027 static HRESULT WINAPI domdoc_load(
2028     IXMLDOMDocument3 *iface,
2029     VARIANT xmlSource,
2030     VARIANT_BOOL* isSuccessful )
2031 {
2032     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2033     LPWSTR filename = NULL;
2034     HRESULT hr = S_FALSE;
2035     IXMLDOMDocument3 *pNewDoc = NULL;
2036     IStream *pStream = NULL;
2037     xmlDocPtr xmldoc;
2038
2039     TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
2040
2041     *isSuccessful = VARIANT_FALSE;
2042
2043     assert( &This->node );
2044
2045     switch( V_VT(&xmlSource) )
2046     {
2047     case VT_BSTR:
2048         filename = V_BSTR(&xmlSource);
2049         break;
2050     case VT_UNKNOWN:
2051         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2052         if(hr == S_OK)
2053         {
2054             if(pNewDoc)
2055             {
2056                 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2057                 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2058                 hr = attach_xmldoc(This, xmldoc);
2059
2060                 if(SUCCEEDED(hr))
2061                     *isSuccessful = VARIANT_TRUE;
2062
2063                 return hr;
2064             }
2065         }
2066         hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2067         if(hr == S_OK)
2068         {
2069             IPersistStream *pDocStream;
2070             hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2071             if(hr == S_OK)
2072             {
2073                 hr = IPersistStream_Load(pDocStream, pStream);
2074                 IStream_Release(pStream);
2075                 if(hr == S_OK)
2076                 {
2077                     *isSuccessful = VARIANT_TRUE;
2078
2079                     TRACE("Using IStream to load Document\n");
2080                     return S_OK;
2081                 }
2082                 else
2083                 {
2084                     ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2085                 }
2086             }
2087             else
2088             {
2089                 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2090             }
2091         }
2092         else
2093         {
2094             /* ISequentialStream */
2095             FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2096         }
2097         break;
2098      default:
2099             FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2100      }
2101
2102     TRACE("filename (%s)\n", debugstr_w(filename));
2103
2104     if ( filename )
2105     {
2106         hr = doread( This, filename );
2107
2108         if ( FAILED(hr) )
2109             This->error = E_FAIL;
2110         else
2111         {
2112             hr = This->error = S_OK;
2113             *isSuccessful = VARIANT_TRUE;
2114         }
2115     }
2116
2117     if(!filename || FAILED(hr)) {
2118         xmldoc = xmlNewDoc(NULL);
2119         xmldoc->_private = create_priv();
2120         hr = attach_xmldoc(This, xmldoc);
2121         if(SUCCEEDED(hr))
2122             hr = S_FALSE;
2123     }
2124
2125     TRACE("ret (%d)\n", hr);
2126
2127     return hr;
2128 }
2129
2130
2131 static HRESULT WINAPI domdoc_get_readyState(
2132     IXMLDOMDocument3 *iface,
2133     LONG *value )
2134 {
2135     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2136     FIXME("stub! (%p)->(%p)\n", This, value);
2137
2138     if (!value)
2139         return E_INVALIDARG;
2140
2141     *value = READYSTATE_COMPLETE;
2142     return S_OK;
2143 }
2144
2145
2146 static HRESULT WINAPI domdoc_get_parseError(
2147     IXMLDOMDocument3 *iface,
2148     IXMLDOMParseError** errorObj )
2149 {
2150     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2151     static const WCHAR err[] = {'e','r','r','o','r',0};
2152     BSTR error_string = NULL;
2153
2154     FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2155
2156     if(This->error)
2157         error_string = SysAllocString(err);
2158
2159     *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2160     if(!*errorObj) return E_OUTOFMEMORY;
2161     return S_OK;
2162 }
2163
2164
2165 static HRESULT WINAPI domdoc_get_url(
2166     IXMLDOMDocument3 *iface,
2167     BSTR* urlString )
2168 {
2169     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2170     FIXME("(%p)->(%p)\n", This, urlString);
2171     return E_NOTIMPL;
2172 }
2173
2174
2175 static HRESULT WINAPI domdoc_get_async(
2176     IXMLDOMDocument3 *iface,
2177     VARIANT_BOOL* isAsync )
2178 {
2179     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2180
2181     TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2182     *isAsync = This->async;
2183     return S_OK;
2184 }
2185
2186
2187 static HRESULT WINAPI domdoc_put_async(
2188     IXMLDOMDocument3 *iface,
2189     VARIANT_BOOL isAsync )
2190 {
2191     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2192
2193     TRACE("(%p)->(%d)\n", This, isAsync);
2194     This->async = isAsync;
2195     return S_OK;
2196 }
2197
2198
2199 static HRESULT WINAPI domdoc_abort(
2200     IXMLDOMDocument3 *iface )
2201 {
2202     domdoc *This = impl_from_IXMLDOMDocument3(iface);
2203     FIXME("%p\n", This);
2204     return E_NOTIMPL;
2205 }
2206
2207
2208 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2209 {
2210     UINT len;
2211     LPSTR str;
2212
2213     len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2214     str = heap_alloc( len );
2215     if ( !str )
2216         return FALSE;
2217     WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2218     *plen = len;
2219     *pstr = str;
2220     return TRUE;
2221 }
2222
2223 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2224 static HRESULT WINAPI domdoc_loadXML(
2225     IXMLDOMDocument3 *iface,
2226     BSTR bstrXML,
2227     VARIANT_BOOL* isSuccessful )
2228 {
2229     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2230     static const xmlChar encoding[] = "UTF-8";
2231     xmlDocPtr xmldoc = NULL;
2232     HRESULT hr = S_FALSE, hr2;
2233     char *str;
2234     int len;
2235
2236     TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2237
2238     assert ( &This->node );
2239
2240     if ( isSuccessful )
2241     {
2242         *isSuccessful = VARIANT_FALSE;
2243
2244         if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2245         {
2246             xmldoc = doparse(This, str, len, encoding);
2247             heap_free( str );
2248             if ( !xmldoc )
2249             {
2250                 This->error = E_FAIL;
2251                 TRACE("failed to parse document\n");
2252             }
2253             else
2254             {
2255                 hr = This->error = S_OK;
2256                 *isSuccessful = VARIANT_TRUE;
2257                 TRACE("parsed document %p\n", xmldoc);
2258             }
2259         }
2260     }
2261     if(!xmldoc)
2262         xmldoc = xmlNewDoc(NULL);
2263
2264     xmldoc->_private = create_priv();
2265
2266     hr2 = attach_xmldoc(This, xmldoc);
2267     if( FAILED(hr2) )
2268         hr = hr2;
2269
2270     return hr;
2271 }
2272
2273 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2274 {
2275     DWORD written = -1;
2276
2277     if(!WriteFile(ctx, buffer, len, &written, NULL))
2278     {
2279         WARN("write error\n");
2280         return -1;
2281     }
2282     else
2283         return written;
2284 }
2285
2286 static int XMLCALL domdoc_save_closecallback(void *ctx)
2287 {
2288     return CloseHandle(ctx) ? 0 : -1;
2289 }
2290
2291 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2292 {
2293     ULONG written = 0;
2294     HRESULT hr;
2295
2296     hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2297     if (hr != S_OK)
2298     {
2299         WARN("stream write error: 0x%08x\n", hr);
2300         return -1;
2301     }
2302     else
2303         return written;
2304 }
2305
2306 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2307 {
2308     IStream_Release((IStream*)ctx);
2309     return 0;
2310 }
2311
2312 static HRESULT WINAPI domdoc_save(
2313     IXMLDOMDocument3 *iface,
2314     VARIANT destination )
2315 {
2316     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2317     xmlSaveCtxtPtr ctx = NULL;
2318     xmlNodePtr xmldecl;
2319     HRESULT ret = S_OK;
2320
2321     TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2322           V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2323
2324     if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2325     {
2326         FIXME("Unhandled vt %d\n", V_VT(&destination));
2327         return S_FALSE;
2328     }
2329
2330     if(V_VT(&destination) == VT_UNKNOWN)
2331     {
2332         IUnknown *pUnk = V_UNKNOWN(&destination);
2333         IXMLDOMDocument2 *document;
2334         IStream *stream;
2335
2336         ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2337         if(ret == S_OK)
2338         {
2339             VARIANT_BOOL success;
2340             BSTR xml;
2341
2342             ret = IXMLDOMDocument3_get_xml(iface, &xml);
2343             if(ret == S_OK)
2344             {
2345                 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2346                 SysFreeString(xml);
2347             }
2348
2349             IXMLDOMDocument3_Release(document);
2350             return ret;
2351         }
2352
2353         ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2354         if(ret == S_OK)
2355         {
2356             ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2357                 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2358
2359             if(!ctx)
2360             {
2361                 IStream_Release(stream);
2362                 return E_FAIL;
2363             }
2364         }
2365     }
2366     else
2367     {
2368         /* save with file path */
2369         HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2370                                     NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2371         if( handle == INVALID_HANDLE_VALUE )
2372         {
2373             WARN("failed to create file\n");
2374             return E_FAIL;
2375         }
2376
2377         /* disable top XML declaration */
2378         ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2379                           handle, NULL, XML_SAVE_NO_DECL);
2380         if (!ctx)
2381         {
2382             CloseHandle(handle);
2383             return E_FAIL;
2384         }
2385     }
2386
2387     xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2388     if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2389     xmldoc_link_xmldecl(get_doc(This), xmldecl);
2390
2391     /* will release resources through close callback */
2392     xmlSaveClose(ctx);
2393
2394     return ret;
2395 }
2396
2397 static HRESULT WINAPI domdoc_get_validateOnParse(
2398     IXMLDOMDocument3 *iface,
2399     VARIANT_BOOL* isValidating )
2400 {
2401     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2402     TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2403     *isValidating = This->validating;
2404     return S_OK;
2405 }
2406
2407
2408 static HRESULT WINAPI domdoc_put_validateOnParse(
2409     IXMLDOMDocument3 *iface,
2410     VARIANT_BOOL isValidating )
2411 {
2412     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2413     TRACE("(%p)->(%d)\n", This, isValidating);
2414     This->validating = isValidating;
2415     return S_OK;
2416 }
2417
2418
2419 static HRESULT WINAPI domdoc_get_resolveExternals(
2420     IXMLDOMDocument3 *iface,
2421     VARIANT_BOOL* isResolving )
2422 {
2423     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2424     TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2425     *isResolving = This->resolving;
2426     return S_OK;
2427 }
2428
2429
2430 static HRESULT WINAPI domdoc_put_resolveExternals(
2431     IXMLDOMDocument3 *iface,
2432     VARIANT_BOOL isResolving )
2433 {
2434     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2435     TRACE("(%p)->(%d)\n", This, isResolving);
2436     This->resolving = isResolving;
2437     return S_OK;
2438 }
2439
2440
2441 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2442     IXMLDOMDocument3 *iface,
2443     VARIANT_BOOL* isPreserving )
2444 {
2445     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2446     TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2447     *isPreserving = This->properties->preserving;
2448     return S_OK;
2449 }
2450
2451
2452 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2453     IXMLDOMDocument3 *iface,
2454     VARIANT_BOOL isPreserving )
2455 {
2456     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2457     TRACE("(%p)->(%d)\n", This, isPreserving);
2458     This->properties->preserving = isPreserving;
2459     return S_OK;
2460 }
2461
2462
2463 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2464     IXMLDOMDocument3 *iface,
2465     VARIANT readyStateChangeSink )
2466 {
2467     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2468     FIXME("%p\n", This);
2469     return E_NOTIMPL;
2470 }
2471
2472
2473 static HRESULT WINAPI domdoc_put_onDataAvailable(
2474     IXMLDOMDocument3 *iface,
2475     VARIANT onDataAvailableSink )
2476 {
2477     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2478     FIXME("%p\n", This);
2479     return E_NOTIMPL;
2480 }
2481
2482 static HRESULT WINAPI domdoc_put_onTransformNode(
2483     IXMLDOMDocument3 *iface,
2484     VARIANT onTransformNodeSink )
2485 {
2486     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2487     FIXME("%p\n", This);
2488     return E_NOTIMPL;
2489 }
2490
2491 static HRESULT WINAPI domdoc_get_namespaces(
2492     IXMLDOMDocument3* iface,
2493     IXMLDOMSchemaCollection** schemaCollection )
2494 {
2495     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496     FIXME("(%p)->(%p)\n", This, schemaCollection);
2497     return E_NOTIMPL;
2498 }
2499
2500 static HRESULT WINAPI domdoc_get_schemas(
2501     IXMLDOMDocument3* iface,
2502     VARIANT* var1 )
2503 {
2504     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505     HRESULT hr = S_FALSE;
2506     IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2507
2508     TRACE("(%p)->(%p)\n", This, var1);
2509
2510     VariantInit(var1); /* Test shows we don't call VariantClear here */
2511     V_VT(var1) = VT_NULL;
2512
2513     if(cur_schema)
2514     {
2515         hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2516         if(SUCCEEDED(hr))
2517             V_VT(var1) = VT_DISPATCH;
2518     }
2519     return hr;
2520 }
2521
2522 static HRESULT WINAPI domdoc_putref_schemas(
2523     IXMLDOMDocument3* iface,
2524     VARIANT var1)
2525 {
2526     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2527     HRESULT hr = E_FAIL;
2528     IXMLDOMSchemaCollection2* new_schema = NULL;
2529
2530     FIXME("(%p): semi-stub\n", This);
2531     switch(V_VT(&var1))
2532     {
2533     case VT_UNKNOWN:
2534         hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2535         break;
2536
2537     case VT_DISPATCH:
2538         hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2539         break;
2540
2541     case VT_NULL:
2542     case VT_EMPTY:
2543         hr = S_OK;
2544         break;
2545
2546     default:
2547         WARN("Can't get schema from vt %x\n", V_VT(&var1));
2548     }
2549
2550     if(SUCCEEDED(hr))
2551     {
2552         IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2553         if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2554     }
2555
2556     return hr;
2557 }
2558
2559 static inline BOOL is_wellformed(xmlDocPtr doc)
2560 {
2561 #ifdef HAVE_XMLDOC_PROPERTIES
2562     return doc->properties & XML_DOC_WELLFORMED;
2563 #else
2564     /* Not a full check, but catches the worst violations */
2565     xmlNodePtr child;
2566     int root = 0;
2567
2568     for (child = doc->children; child != NULL; child = child->next)
2569     {
2570         switch (child->type)
2571         {
2572         case XML_ELEMENT_NODE:
2573             if (++root > 1)
2574                 return FALSE;
2575             break;
2576         case XML_TEXT_NODE:
2577         case XML_CDATA_SECTION_NODE:
2578             return FALSE;
2579             break;
2580         default:
2581             break;
2582         }
2583     }
2584
2585     return root == 1;
2586 #endif
2587 }
2588
2589 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2590 {
2591     va_list ap;
2592     va_start(ap, msg);
2593     LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2594     va_end(ap);
2595 }
2596
2597 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2598 {
2599     va_list ap;
2600     va_start(ap, msg);
2601     LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2602     va_end(ap);
2603 }
2604
2605 static HRESULT WINAPI domdoc_validateNode(
2606     IXMLDOMDocument3* iface,
2607     IXMLDOMNode* node,
2608     IXMLDOMParseError** err)
2609 {
2610     domdoc* This = impl_from_IXMLDOMDocument3(iface);
2611     LONG state, err_code = 0;
2612     HRESULT hr = S_OK;
2613     int validated = 0;
2614
2615     TRACE("(%p)->(%p, %p)\n", This, node, err);
2616     domdoc_get_readyState(iface, &state);
2617     if (state != READYSTATE_COMPLETE)
2618     {
2619         if (err)
2620            *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2621         return E_PENDING;
2622     }
2623
2624     if (!node)
2625     {
2626         if (err)
2627             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2628         return E_POINTER;
2629     }
2630
2631     if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2632     {
2633         if (err)
2634             *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2635         return E_FAIL;
2636     }
2637
2638     if (!is_wellformed(get_doc(This)))
2639     {
2640         ERR("doc not well-formed");
2641         if (err)
2642             *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2643         return S_FALSE;
2644     }
2645
2646     /* DTD validation */
2647     if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2648     {
2649         xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2650         vctx->error = validate_error;
2651         vctx->warning = validate_warning;
2652         ++validated;
2653
2654         if (!((node == (IXMLDOMNode*)iface)?
2655               xmlValidateDocument(vctx, get_doc(This)) :
2656               xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2657         {
2658             /* TODO: get a real error code here */
2659             TRACE("DTD validation failed\n");
2660             err_code = E_XML_INVALID;
2661             hr = S_FALSE;
2662         }
2663         xmlFreeValidCtxt(vctx);
2664     }
2665
2666     /* Schema validation */
2667     if (hr == S_OK && This->properties->schemaCache != NULL)
2668     {
2669
2670         hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2671         if (!FAILED(hr))
2672         {
2673             ++validated;
2674             /* TODO: get a real error code here */
2675             if (hr == S_OK)
2676             {
2677                 TRACE("schema validation succeeded\n");
2678             }
2679             else
2680             {
2681                 ERR("schema validation failed\n");
2682                 err_code = E_XML_INVALID;
2683             }
2684         }
2685         else
2686         {
2687             /* not really OK, just didn't find a schema for the ns */
2688             hr = S_OK;
2689         }
2690     }
2691
2692     if (!validated)
2693     {
2694         ERR("no DTD or schema found\n");
2695         err_code = E_XML_NODTD;
2696         hr = S_FALSE;
2697     }
2698
2699     if (err)
2700         *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2701
2702     return hr;
2703 }
2704
2705 static HRESULT WINAPI domdoc_validate(
2706     IXMLDOMDocument3* iface,
2707     IXMLDOMParseError** err)
2708 {
2709     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2710     TRACE("(%p)->(%p)\n", This, err);
2711     return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2712 }
2713
2714 static HRESULT WINAPI domdoc_setProperty(
2715     IXMLDOMDocument3* iface,
2716     BSTR p,
2717     VARIANT var)
2718 {
2719     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2720
2721     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2722
2723     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2724     {
2725         VARIANT varStr;
2726         HRESULT hr;
2727         BSTR bstr;
2728
2729         V_VT(&varStr) = VT_EMPTY;
2730         if (V_VT(&var) != VT_BSTR)
2731         {
2732             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2733                 return hr;
2734             bstr = V_BSTR(&varStr);
2735         }
2736         else
2737             bstr = V_BSTR(&var);
2738
2739         hr = S_OK;
2740         if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2741             This->properties->XPath = TRUE;
2742         else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2743             This->properties->XPath = FALSE;
2744         else
2745             hr = E_FAIL;
2746
2747         VariantClear(&varStr);
2748         return hr;
2749     }
2750     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2751     {
2752         VARIANT varStr;
2753         HRESULT hr;
2754         BSTR bstr;
2755         xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2756         xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2757         xmlXPathContextPtr ctx;
2758         struct list *pNsList;
2759         select_ns_entry* pNsEntry = NULL;
2760
2761         V_VT(&varStr) = VT_EMPTY;
2762         if (V_VT(&var) != VT_BSTR)
2763         {
2764             if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2765                 return hr;
2766             bstr = V_BSTR(&varStr);
2767         }
2768         else
2769             bstr = V_BSTR(&var);
2770
2771         hr = S_OK;
2772
2773         pNsList = &(This->properties->selectNsList);
2774         clear_selectNsList(pNsList);
2775         heap_free(nsStr);
2776         nsStr = xmlChar_from_wchar(bstr);
2777
2778
2779         TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2780
2781         This->properties->selectNsStr = nsStr;
2782         This->properties->selectNsStr_len = xmlStrlen(nsStr);
2783         if (bstr && *bstr)
2784         {
2785             ctx = xmlXPathNewContext(This->node.node->doc);
2786             pTokBegin = nsStr;
2787             pTokEnd = nsStr;
2788             for (; *pTokBegin; pTokBegin = pTokEnd)
2789             {
2790                 if (pNsEntry != NULL)
2791                     memset(pNsEntry, 0, sizeof(select_ns_entry));
2792                 else
2793                     pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2794
2795                 while (*pTokBegin == ' ')
2796                     ++pTokBegin;
2797                 pTokEnd = pTokBegin;
2798                 while (*pTokEnd != ' ' && *pTokEnd != 0)
2799                     ++pTokEnd;
2800
2801                 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2802                 {
2803                     hr = E_FAIL;
2804                     WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2805                           wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2806                     continue;
2807                 }
2808
2809                 pTokBegin += 5;
2810                 if (*pTokBegin == '=')
2811                 {
2812                     /*valid for XSLPattern?*/
2813                     FIXME("Setting default xmlns not supported - skipping.\n");
2814                     pTokBegin = pTokEnd;
2815                     continue;
2816                 }
2817                 else if (*pTokBegin == ':')
2818                 {
2819                     pNsEntry->prefix = ++pTokBegin;
2820                     for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2821                         ;
2822
2823                     if (pTokInner == pTokEnd)
2824                     {
2825                         hr = E_FAIL;
2826                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2827                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2828                         continue;
2829                     }
2830
2831                     pNsEntry->prefix_end = *pTokInner;
2832                     *pTokInner = 0;
2833                     ++pTokInner;
2834
2835                     if (pTokEnd-pTokInner > 1 &&
2836                         ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2837                          (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2838                     {
2839                         pNsEntry->href = ++pTokInner;
2840                         pNsEntry->href_end = *(pTokEnd-1);
2841                         *(pTokEnd-1) = 0;
2842                         list_add_tail(pNsList, &pNsEntry->entry);
2843                         /*let libxml figure out if they're valid from here ;)*/
2844                         if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2845                         {
2846                             hr = E_FAIL;
2847                         }
2848                         pNsEntry = NULL;
2849                         continue;
2850                     }
2851                     else
2852                     {
2853                         WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2854                               wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2855                         list_add_tail(pNsList, &pNsEntry->entry);
2856
2857                         pNsEntry = NULL;
2858                         hr = E_FAIL;
2859                         continue;
2860                     }
2861                 }
2862                 else
2863                 {
2864                     hr = E_FAIL;
2865                     continue;
2866                 }
2867             }
2868             heap_free(pNsEntry);
2869             xmlXPathFreeContext(ctx);
2870         }
2871
2872         VariantClear(&varStr);
2873         return hr;
2874     }
2875     else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2876              lstrcmpiW(p, PropertyNewParserW) == 0)
2877     {
2878         /* Ignore */
2879         FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2880         return S_OK;
2881     }
2882
2883     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2884     return E_FAIL;
2885 }
2886
2887 static HRESULT WINAPI domdoc_getProperty(
2888     IXMLDOMDocument3* iface,
2889     BSTR p,
2890     VARIANT* var)
2891 {
2892     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2893
2894     TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2895
2896     if (!var)
2897         return E_INVALIDARG;
2898
2899     if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2900     {
2901         V_VT(var) = VT_BSTR;
2902         V_BSTR(var) = This->properties->XPath ?
2903                       SysAllocString(PropValueXPathW) :
2904                       SysAllocString(PropValueXSLPatternW);
2905         return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2906     }
2907     else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2908     {
2909         int lenA, lenW;
2910         BSTR rebuiltStr, cur;
2911         const xmlChar *nsStr;
2912         struct list *pNsList;
2913         select_ns_entry* pNsEntry;
2914
2915         V_VT(var) = VT_BSTR;
2916         nsStr = This->properties->selectNsStr;
2917         pNsList = &This->properties->selectNsList;
2918         lenA = This->properties->selectNsStr_len;
2919         lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2920         rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2921         MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2922         cur = rebuiltStr;
2923         /* this is fine because all of the chars that end tokens are ASCII*/
2924         LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2925         {
2926             while (*cur != 0) ++cur;
2927             if (pNsEntry->prefix_end)
2928             {
2929                 *cur = pNsEntry->prefix_end;
2930                 while (*cur != 0) ++cur;
2931             }
2932
2933             if (pNsEntry->href_end)
2934             {
2935                 *cur = pNsEntry->href_end;
2936             }
2937         }
2938         V_BSTR(var) = SysAllocString(rebuiltStr);
2939         heap_free(rebuiltStr);
2940         return S_OK;
2941     }
2942
2943     FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2944     return E_FAIL;
2945 }
2946
2947 static HRESULT WINAPI domdoc_importNode(
2948     IXMLDOMDocument3* iface,
2949     IXMLDOMNode* node,
2950     VARIANT_BOOL deep,
2951     IXMLDOMNode** clone)
2952 {
2953     domdoc *This = impl_from_IXMLDOMDocument3( iface );
2954     FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2955     return E_NOTIMPL;
2956 }
2957
2958 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2959 {
2960     domdoc_QueryInterface,
2961     domdoc_AddRef,
2962     domdoc_Release,
2963     domdoc_GetTypeInfoCount,
2964     domdoc_GetTypeInfo,
2965     domdoc_GetIDsOfNames,
2966     domdoc_Invoke,
2967     domdoc_get_nodeName,
2968     domdoc_get_nodeValue,
2969     domdoc_put_nodeValue,
2970     domdoc_get_nodeType,
2971     domdoc_get_parentNode,
2972     domdoc_get_childNodes,
2973     domdoc_get_firstChild,
2974     domdoc_get_lastChild,
2975     domdoc_get_previousSibling,
2976     domdoc_get_nextSibling,
2977     domdoc_get_attributes,
2978     domdoc_insertBefore,
2979     domdoc_replaceChild,
2980     domdoc_removeChild,
2981     domdoc_appendChild,
2982     domdoc_hasChildNodes,
2983     domdoc_get_ownerDocument,
2984     domdoc_cloneNode,
2985     domdoc_get_nodeTypeString,
2986     domdoc_get_text,
2987     domdoc_put_text,
2988     domdoc_get_specified,
2989     domdoc_get_definition,
2990     domdoc_get_nodeTypedValue,
2991     domdoc_put_nodeTypedValue,
2992     domdoc_get_dataType,
2993     domdoc_put_dataType,
2994     domdoc_get_xml,
2995     domdoc_transformNode,
2996     domdoc_selectNodes,
2997     domdoc_selectSingleNode,
2998     domdoc_get_parsed,
2999     domdoc_get_namespaceURI,
3000     domdoc_get_prefix,
3001     domdoc_get_baseName,
3002     domdoc_transformNodeToObject,
3003     domdoc_get_doctype,
3004     domdoc_get_implementation,
3005     domdoc_get_documentElement,
3006     domdoc_put_documentElement,
3007     domdoc_createElement,
3008     domdoc_createDocumentFragment,
3009     domdoc_createTextNode,
3010     domdoc_createComment,
3011     domdoc_createCDATASection,
3012     domdoc_createProcessingInstruction,
3013     domdoc_createAttribute,
3014     domdoc_createEntityReference,
3015     domdoc_getElementsByTagName,
3016     domdoc_createNode,
3017     domdoc_nodeFromID,
3018     domdoc_load,
3019     domdoc_get_readyState,
3020     domdoc_get_parseError,
3021     domdoc_get_url,
3022     domdoc_get_async,
3023     domdoc_put_async,
3024     domdoc_abort,
3025     domdoc_loadXML,
3026     domdoc_save,
3027     domdoc_get_validateOnParse,
3028     domdoc_put_validateOnParse,
3029     domdoc_get_resolveExternals,
3030     domdoc_put_resolveExternals,
3031     domdoc_get_preserveWhiteSpace,
3032     domdoc_put_preserveWhiteSpace,
3033     domdoc_put_onReadyStateChange,
3034     domdoc_put_onDataAvailable,
3035     domdoc_put_onTransformNode,
3036     domdoc_get_namespaces,
3037     domdoc_get_schemas,
3038     domdoc_putref_schemas,
3039     domdoc_validate,
3040     domdoc_setProperty,
3041     domdoc_getProperty,
3042     domdoc_validateNode,
3043     domdoc_importNode
3044 };
3045
3046 /* IConnectionPointContainer */
3047 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3048                                                               REFIID riid, void **ppv)
3049 {
3050     domdoc *This = impl_from_IConnectionPointContainer(iface);
3051     return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3052 }
3053
3054 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3055 {
3056     domdoc *This = impl_from_IConnectionPointContainer(iface);
3057     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3058 }
3059
3060 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3061 {
3062     domdoc *This = impl_from_IConnectionPointContainer(iface);
3063     return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3064 }
3065
3066 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3067         IEnumConnectionPoints **ppEnum)
3068 {
3069     domdoc *This = impl_from_IConnectionPointContainer(iface);
3070     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3071     return E_NOTIMPL;
3072 }
3073
3074 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3075         REFIID riid, IConnectionPoint **cp)
3076 {
3077     domdoc *This = impl_from_IConnectionPointContainer(iface);
3078     ConnectionPoint *iter;
3079
3080     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3081
3082     *cp = NULL;
3083
3084     for(iter = This->cp_list; iter; iter = iter->next)
3085     {
3086         if (IsEqualGUID(iter->iid, riid))
3087             *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3088     }
3089
3090     if (*cp)
3091     {
3092         IConnectionPoint_AddRef(*cp);
3093         return S_OK;
3094     }
3095
3096     FIXME("unsupported riid %s\n", debugstr_guid(riid));
3097     return CONNECT_E_NOCONNECTION;
3098
3099 }
3100
3101 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3102 {
3103     ConnectionPointContainer_QueryInterface,
3104     ConnectionPointContainer_AddRef,
3105     ConnectionPointContainer_Release,
3106     ConnectionPointContainer_EnumConnectionPoints,
3107     ConnectionPointContainer_FindConnectionPoint
3108 };
3109
3110 /* IConnectionPoint */
3111 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3112                                                      REFIID riid, void **ppv)
3113 {
3114     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3115
3116     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3117
3118     *ppv = NULL;
3119
3120     if (IsEqualGUID(&IID_IUnknown, riid) ||
3121         IsEqualGUID(&IID_IConnectionPoint, riid))
3122     {
3123         *ppv = iface;
3124     }
3125
3126     if (*ppv)
3127     {
3128         IConnectionPoint_AddRef(iface);
3129         return S_OK;
3130     }
3131
3132     WARN("Unsupported interface %s\n", debugstr_guid(riid));
3133     return E_NOINTERFACE;
3134 }
3135
3136 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3137 {
3138     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3139     return IConnectionPointContainer_AddRef(This->container);
3140 }
3141
3142 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3143 {
3144     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3145     return IConnectionPointContainer_Release(This->container);
3146 }
3147
3148 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3149 {
3150     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3151
3152     TRACE("(%p)->(%p)\n", This, iid);
3153
3154     if (!iid) return E_POINTER;
3155
3156     *iid = *This->iid;
3157     return S_OK;
3158 }
3159
3160 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3161         IConnectionPointContainer **container)
3162 {
3163     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3164
3165     TRACE("(%p)->(%p)\n", This, container);
3166
3167     if (!container) return E_POINTER;
3168
3169     *container = This->container;
3170     IConnectionPointContainer_AddRef(*container);
3171     return S_OK;
3172 }
3173
3174 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3175                                              DWORD *pdwCookie)
3176 {
3177     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3178     FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3179     return E_NOTIMPL;
3180 }
3181
3182 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3183 {
3184     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3185
3186     TRACE("(%p)->(%d)\n", This, cookie);
3187
3188     if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3189         return CONNECT_E_NOCONNECTION;
3190
3191     IUnknown_Release(This->sinks[cookie-1].unk);
3192     This->sinks[cookie-1].unk = NULL;
3193
3194     return S_OK;
3195 }
3196
3197 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3198                                                       IEnumConnections **ppEnum)
3199 {
3200     ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3201     FIXME("(%p)->(%p): stub\n", This, ppEnum);
3202     return E_NOTIMPL;
3203 }
3204
3205 static const IConnectionPointVtbl ConnectionPointVtbl =
3206 {
3207     ConnectionPoint_QueryInterface,
3208     ConnectionPoint_AddRef,
3209     ConnectionPoint_Release,
3210     ConnectionPoint_GetConnectionInterface,
3211     ConnectionPoint_GetConnectionPointContainer,
3212     ConnectionPoint_Advise,
3213     ConnectionPoint_Unadvise,
3214     ConnectionPoint_EnumConnections
3215 };
3216
3217 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3218 {
3219     cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3220     cp->doc = doc;
3221     cp->iid = riid;
3222     cp->sinks = NULL;
3223     cp->sinks_size = 0;
3224
3225     cp->next = doc->cp_list;
3226     doc->cp_list = cp;
3227
3228     cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3229 }
3230
3231 /* domdoc implementation of IObjectWithSite */
3232 static HRESULT WINAPI
3233 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3234 {
3235     domdoc *This = impl_from_IObjectWithSite(iface);
3236     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3237 }
3238
3239 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3240 {
3241     domdoc *This = impl_from_IObjectWithSite(iface);
3242     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3243 }
3244
3245 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3246 {
3247     domdoc *This = impl_from_IObjectWithSite(iface);
3248     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3249 }
3250
3251 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3252 {
3253     domdoc *This = impl_from_IObjectWithSite(iface);
3254
3255     TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3256
3257     if ( !This->site )
3258         return E_FAIL;
3259
3260     return IUnknown_QueryInterface( This->site, iid, ppvSite );
3261 }
3262
3263 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3264 {
3265     domdoc *This = impl_from_IObjectWithSite(iface);
3266
3267     TRACE("(%p)->(%p)\n", iface, punk);
3268
3269     if(!punk)
3270     {
3271         if(This->site)
3272         {
3273             IUnknown_Release( This->site );
3274             This->site = NULL;
3275         }
3276
3277         return S_OK;
3278     }
3279
3280     IUnknown_AddRef( punk );
3281
3282     if(This->site)
3283         IUnknown_Release( This->site );
3284
3285     This->site = punk;
3286
3287     return S_OK;
3288 }
3289
3290 static const IObjectWithSiteVtbl domdocObjectSite =
3291 {
3292     domdoc_ObjectWithSite_QueryInterface,
3293     domdoc_ObjectWithSite_AddRef,
3294     domdoc_ObjectWithSite_Release,
3295     domdoc_ObjectWithSite_SetSite,
3296     domdoc_ObjectWithSite_GetSite
3297 };
3298
3299 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3300 {
3301     domdoc *This = impl_from_IObjectSafety(iface);
3302     return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3303 }
3304
3305 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3306 {
3307     domdoc *This = impl_from_IObjectSafety(iface);
3308     return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3309 }
3310
3311 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3312 {
3313     domdoc *This = impl_from_IObjectSafety(iface);
3314     return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3315 }
3316
3317 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3318
3319 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3320         DWORD *supported, DWORD *enabled)
3321 {
3322     domdoc *This = impl_from_IObjectSafety(iface);
3323
3324     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3325
3326     if(!supported || !enabled) return E_POINTER;
3327
3328     *supported = SAFETY_SUPPORTED_OPTIONS;
3329     *enabled = This->safeopt;
3330
3331     return S_OK;
3332 }
3333
3334 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3335         DWORD mask, DWORD enabled)
3336 {
3337     domdoc *This = impl_from_IObjectSafety(iface);
3338     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3339
3340     if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3341         return E_FAIL;
3342
3343     This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3344     return S_OK;
3345 }
3346
3347 #undef SAFETY_SUPPORTED_OPTIONS
3348
3349 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3350     domdoc_Safety_QueryInterface,
3351     domdoc_Safety_AddRef,
3352     domdoc_Safety_Release,
3353     domdoc_Safety_GetInterfaceSafetyOptions,
3354     domdoc_Safety_SetInterfaceSafetyOptions
3355 };
3356
3357 static const tid_t domdoc_iface_tids[] = {
3358     IXMLDOMNode_tid,
3359     IXMLDOMDocument_tid,
3360     IXMLDOMDocument2_tid,
3361     0
3362 };
3363 static dispex_static_data_t domdoc_dispex = {
3364     NULL,
3365     IXMLDOMDocument2_tid,
3366     NULL,
3367     domdoc_iface_tids
3368 };
3369
3370 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3371 {
3372     domdoc *doc;
3373
3374     doc = heap_alloc( sizeof (*doc) );
3375     if( !doc )
3376         return E_OUTOFMEMORY;
3377
3378     doc->lpVtbl = &domdoc_vtbl;
3379     doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3380     doc->lpvtblIObjectWithSite = &domdocObjectSite;
3381     doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3382     doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3383     doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3384     doc->ref = 1;
3385     doc->async = VARIANT_TRUE;
3386     doc->validating = 0;
3387     doc->resolving = 0;
3388     doc->properties = properties_from_xmlDocPtr(xmldoc);
3389     doc->error = S_OK;
3390     doc->stream = NULL;
3391     doc->site = NULL;
3392     doc->safeopt = 0;
3393     doc->bsc = NULL;
3394     doc->cp_list = NULL;
3395
3396     /* events connection points */
3397     ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3398     ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3399     ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3400
3401     init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3402
3403     *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3404
3405     TRACE("returning iface %p\n", *document);
3406     return S_OK;
3407 }
3408
3409 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3410 {
3411     xmlDocPtr xmldoc;
3412     HRESULT hr;
3413
3414     TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3415
3416     xmldoc = xmlNewDoc(NULL);
3417     if(!xmldoc)
3418         return E_OUTOFMEMORY;
3419
3420     xmldoc->_private = create_priv();
3421     priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3422
3423     hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3424     if(FAILED(hr))
3425     {
3426         free_properties(properties_from_xmlDocPtr(xmldoc));
3427         heap_free(xmldoc->_private);
3428         xmlFreeDoc(xmldoc);
3429         return hr;
3430     }
3431
3432     return hr;
3433 }
3434
3435 IUnknown* create_domdoc( xmlNodePtr document )
3436 {
3437     void* pObj = NULL;
3438     HRESULT hr;
3439
3440     TRACE("(%p)\n", document);
3441
3442     hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3443     if (FAILED(hr))
3444         return NULL;
3445
3446     return pObj;
3447 }
3448
3449 #else
3450
3451 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3452 {
3453     MESSAGE("This program tried to use a DOMDocument object, but\n"
3454             "libxml2 support was not present at compile time.\n");
3455     return E_NOTIMPL;
3456 }
3457
3458 #endif