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