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